From 41a129bb9026ea7dd3d23b2e78438b202626ac1a Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 22 May 2026 11:04:54 +0200 Subject: [PATCH 01/11] init commit --- cli/src/zshell/subcommands/record.py | 259 +++++++++++++++++++++++++-- 1 file changed, 244 insertions(+), 15 deletions(-) diff --git a/cli/src/zshell/subcommands/record.py b/cli/src/zshell/subcommands/record.py index 328e2bf..f0ef76b 100644 --- a/cli/src/zshell/subcommands/record.py +++ b/cli/src/zshell/subcommands/record.py @@ -1,16 +1,245 @@ -# import typer -# import subprocess -# -# from typing import Optional -# -# app = typer.Typer() -# -# RECORDER = "gpu-screen-recorder" -# HOME = str(os.getenv("HOME")) -# CONFIG = Path(HOME + "/.config/zshell/config.json") -# -# -# @app.command() -# def start(): +#!/usr/bin/env python3 +import os +import json +import subprocess +import time +import signal +from pathlib import Path +from typing import Optional -# TODO: Currently unused +import typer + +app = typer.Typer() + +RECORDER = "gpu-screen-recorder" +HOME = str(os.getenv("HOME", str(Path.home()))) +CONFIG = Path(HOME) / ".config/zshell/config.json" + +# Paths for temp recording and notifications +STATE_DIR = Path(HOME) / ".local/state/zshell/record" +TEMP_RECORDING = STATE_DIR / "recording.mp4" +NOTIF_ID_FILE = STATE_DIR / "notifid.txt" + +# Where final recordings are saved +RECORDINGS_DIR = os.getenv("ZSHELL_RECORDINGS_DIR", + str(Path(HOME) / "Videos/Recordings")) + + +# ── helpers ────────────────────────────────────────────── +def _read_extra_args() -> list[str]: + """Return extra gpu-screen-recorder arguments from the user config.""" + try: + if CONFIG.is_file(): + data = json.loads(CONFIG.read_text()) + return data.get("record", {}).get("extraArgs", []) + except Exception: + pass + return [] + + +def _is_recording() -> bool: + """Check if gpu-screen-recorder process exists.""" + return subprocess.run(["pidof", RECORDER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0 + + +def _notify(summary: str, body: str = "", actions: list = None, timeout: int = 3000) -> Optional[int]: + """Send a desktop notification. Returns the notification ID or None.""" + args = ["notify-send", summary, body, "-t", str(timeout), "-p"] + if actions: + for action in actions: + args.extend(["-A", action]) + try: + proc = subprocess.run(args, capture_output=True, text=True) + return int(proc.stdout.strip()) if proc.stdout.strip().isdigit() else None + except Exception: + return None + + +def _close_notification(notif_id: int): + """Close a notification by its ID.""" + subprocess.run(["notify-send", "--close", str(notif_id)], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def _get_monitors() -> list[dict]: + """Get monitor info from Hyprland.""" + try: + res = subprocess.run(["hyprctl", "monitors", "-j"], + capture_output=True, text=True) + return json.loads(res.stdout) + except Exception: + return [] + + +def _focused_monitor_name() -> Optional[str]: + """Return name of the currently focused monitor.""" + monitors = _get_monitors() + for m in monitors: + if m.get("focused"): + return m["name"] + return None + + +def _monitors_intersecting_region(x: int, y: int, w: int, h: int) -> list[dict]: + """Return monitors whose area intersects the given region.""" + region = (x, y, x + w, y + h) + intersecting = [] + for m in _get_monitors(): + mx, my, mw, mh = m["x"], m["y"], m["width"], m["height"] + if not (region[2] <= mx or region[0] >= mx + mw or region[3] <= my or region[1] >= my + mh): + intersecting.append(m) + return intersecting + + +def _highest_refresh(monitors: list[dict]) -> float: + """Return the maximum refresh rate among the given monitors.""" + return max((m["refreshRate"] for m in monitors), default=60.0) + + +def _slurp_region() -> Optional[str]: + """Call slurp and return geometry like 'WxH+X+Y'.""" + try: + return subprocess.check_output(["slurp", "-f", "%wx%h+%x+%y"], text=True).strip() + except subprocess.CalledProcessError: + return None + + +def _parse_geometry(geometry: str) -> Optional[tuple[int, int, int, int]]: + """Parse 'WxH+X+Y' into (x,y,w,h).""" + import re + match = re.match(r"(\d+)x(\d+)\+(\d+)\+(\d+)", geometry) + if match: + return int(match.group(3)), int(match.group(4)), int(match.group(1)), int(match.group(2)) + return None + + +# ── core actions ───────────────────────────────────────── +def start_recording(region: Optional[str], sound: bool): + """Launch gpu-screen-recorder.""" + STATE_DIR.mkdir(parents=True, exist_ok=True) + + cmd = [RECORDER, "-w"] # -w for window/display + extra_args = _read_extra_args() + + if region: + if region.lower() == "slurp" or not region: + geometry = _slurp_region() + if not geometry: + typer.echo("Region selection cancelled.") + raise typer.Abort() + else: + geometry = region + parsed = _parse_geometry(geometry) + if parsed: + x, y, w, h = parsed + monitors = _monitors_intersecting_region(x, y, w, h) + framerate = _highest_refresh(monitors) + cmd.extend(["-region", geometry, "-f", str(int(framerate))]) + else: + typer.echo("Invalid geometry format.") + raise typer.Abort() + else: + # Fullscreen: use focused monitor + monitor = _focused_monitor_name() + if monitor: + cmd.extend(["-m", monitor]) + # Refresh rate comes from that monitor + monitors = _get_monitors() + mon = next((m for m in monitors if m["name"] == monitor), None) + if mon: + cmd.extend(["-f", str(int(mon["refreshRate"]))]) + + if sound: + cmd.append("-a") + cmd.append("default_output") + + cmd.extend(extra_args) + cmd.append(str(TEMP_RECORDING)) + + # Launch detached + subprocess.Popen(cmd, start_new_session=True, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + # Notification + notif_id = _notify("Recording started", f"Saving to {TEMP_RECORDING}") + if notif_id is not None: + NOTIF_ID_FILE.write_text(str(notif_id)) + + # Early failure check + time.sleep(1) + if not _is_recording(): + _notify("Recording failed", + "Check gpu-screen-recorder output.", timeout=5000) + raise typer.Exit(code=1) + + +def stop_recording(clipboard: bool): + """Stop the recording and finalise the file.""" + # Kill the process + subprocess.run(["pkill", "-f", RECORDER], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + # Wait until it really stops + for _ in range(50): # 5 seconds max + if not _is_recording(): + break + time.sleep(0.1) + + # Move the recording + dest_dir = Path(RECORDINGS_DIR) + dest_dir.mkdir(parents=True, exist_ok=True) + timestamp = time.strftime("%Y-%m-%d_%H-%M-%S") + final_path = dest_dir / f"recording_{timestamp}.mp4" + if TEMP_RECORDING.exists(): + TEMP_RECORDING.rename(final_path) + + # Close the start notification + if NOTIF_ID_FILE.is_file(): + try: + _close_notification(int(NOTIF_ID_FILE.read_text().strip())) + except Exception: + pass + NOTIF_ID_FILE.unlink() + + # Clipboard + if clipboard: + subprocess.run(["wl-copy", "--type", "text/uri-list", f"file://{final_path}"], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + # Final notification (simplified: no actions) + _notify("Recording stopped", f"Saved to {final_path}", timeout=5000) + + +def toggle_pause(): + """Send SIGUSR2 to gpu-screen-recorder.""" + subprocess.run(["pkill", "-USR2", "-f", RECORDER], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + typer.echo("Toggled pause.") + + +# ── Typer command ──────────────────────────────────────── +@app.command() +def record( + region: Optional[str] = typer.Option( + None, "--region", "-r", + help="Record a region. Use 'slurp' (or omit value) to select interactively, or give 'WxH+X+Y'.", + ), + sound: bool = typer.Option( + False, "--sound", "-s", help="Record audio from default output."), + pause: bool = typer.Option( + False, "--pause", "-p", help="Toggle pause/resume."), + clipboard: bool = typer.Option( + False, "--clipboard", "-c", help="Copy the final recording path to clipboard."), +): + """ + Start or stop a screen recording with gpu-screen-recorder. + Running again stops the current recording. + """ + if pause: + toggle_pause() + raise typer.Exit() + + if _is_recording(): + stop_recording(clipboard) + else: + start_recording(region, sound) From ec5e6d3995f82d6382e82758bcc3020887cd91cb Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 22 May 2026 11:06:17 +0200 Subject: [PATCH 02/11] add typer command --- cli/src/zshell/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/src/zshell/__init__.py b/cli/src/zshell/__init__.py index 1b062a4..365e8d8 100644 --- a/cli/src/zshell/__init__.py +++ b/cli/src/zshell/__init__.py @@ -1,6 +1,6 @@ from __future__ import annotations import typer -from zshell.subcommands import shell, scheme, screenshot, wallpaper +from zshell.subcommands import shell, scheme, screenshot, wallpaper, record app = typer.Typer() @@ -8,6 +8,7 @@ app.add_typer(shell.app, name="shell") app.add_typer(scheme.app, name="scheme") app.add_typer(screenshot.app, name="screenshot") app.add_typer(wallpaper.app, name="wallpaper") +app.add_typer(record.app, name="record") # app.add_typer(preset.app, name="preset") From 0ec426e0f07ed52c28affa9ec866874e0d100385 Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 22 May 2026 12:51:06 +0200 Subject: [PATCH 03/11] Record module added to sidebar, file list and buttons. Region recording is broken --- Helpers/Recorder.qml | 123 +++++--- .../Sidebar/Utils/Cards/Record.qml | 290 ++++++++++++++++++ .../Sidebar/Utils/Cards/RecordingList.qml | 226 ++++++++++++++ .../Notifications/Sidebar/Utils/Content.qml | 13 +- cli/pyproject.toml | 1 + .../__pycache__/scheme.cpython-313.pyc | Bin 7101 -> 24035 bytes .../__pycache__/screenshot.cpython-313.pyc | Bin 978 -> 965 bytes .../__pycache__/shell.cpython-313.pyc | Bin 2184 -> 2181 bytes .../__pycache__/wallpaper.cpython-313.pyc | Bin 1920 -> 1983 bytes cli/src/zshell/subcommands/record.py | 81 ++--- .../schemepalettes.cpython-313.pyc | Bin 1388 -> 1388 bytes 11 files changed, 634 insertions(+), 100 deletions(-) create mode 100644 Modules/Notifications/Sidebar/Utils/Cards/Record.qml create mode 100644 Modules/Notifications/Sidebar/Utils/Cards/RecordingList.qml diff --git a/Helpers/Recorder.qml b/Helpers/Recorder.qml index 4c7b330..128c65b 100644 --- a/Helpers/Recorder.qml +++ b/Helpers/Recorder.qml @@ -1,41 +1,82 @@ -// pragma Singleton -// -// import Quickshell -// import QtQuick -// -// Singleton { -// id: root -// -// function start(extraArgs = []): void { -// needsStart = true; -// startArgs = extraArgs; -// checkProc.running = true; -// } -// -// PersistentProperties { -// id: props -// -// property real elapsed: 0 -// property bool paused: false -// property bool running: false -// -// reloadableId: "recorder" -// } -// -// Process { -// id: checkProc -// -// command: ["pidof", "gpu-screen-recorder"] -// running: true -// -// onExited: code => { -// props.running = code === 0; -// -// if (code === 0) { -// if (root.needsStop) { -// Quickshell.execDetached(["zshell-cli"]); -// } -// } -// } -// } -// } +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + readonly property alias elapsed: props.elapsed + property bool needsPause + property bool needsStart + property bool needsStop + readonly property alias paused: props.paused + readonly property alias running: props.running + property list startArgs + + function start(extraArgs = []): void { + needsStart = true; + startArgs = extraArgs; + checkProc.running = true; + } + + function stop(): void { + needsStop = true; + checkProc.running = true; + } + + function togglePause(): void { + needsPause = true; + checkProc.running = true; + } + + PersistentProperties { + id: props + + property real elapsed: 0 + property bool paused: false + property bool running: false + + reloadableId: "recorder" + } + + Process { + id: checkProc + + command: ["pidof", "gpu-screen-recorder"] + running: true + + onExited: code => { + props.running = code === 0; + + if (code === 0) { + if (root.needsStop) { + Quickshell.execDetached(["zshell-cli", "record", "record"]); + props.running = false; + props.paused = false; + } else if (root.needsPause) { + Quickshell.execDetached(["zshell-cli", "record", "record", "-p"]); + props.paused = !props.paused; + } + } else if (root.needsStart) { + Quickshell.execDetached(["zshell-cli", "record", "record", ...root.startArgs]); + props.running = true; + props.paused = false; + props.elapsed = 0; + } + + root.needsStart = false; + root.needsStop = false; + root.needsPause = false; + } + } + + Connections { + function onSecondsChanged(): void { + props.elapsed++; + } + + target: Time // qmllint disable incompatible-type + } +} diff --git a/Modules/Notifications/Sidebar/Utils/Cards/Record.qml b/Modules/Notifications/Sidebar/Utils/Cards/Record.qml new file mode 100644 index 0000000..7d7c832 --- /dev/null +++ b/Modules/Notifications/Sidebar/Utils/Cards/Record.qml @@ -0,0 +1,290 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +CustomRect { + id: root + + required property var props + required property PersistentProperties visibilities + + Layout.fillWidth: true + color: DynamicColors.tPalette.m3surfaceContainer + implicitHeight: layout.implicitHeight + layout.anchors.margins * 2 + radius: Appearance.rounding.smallest + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + RowLayout { + spacing: Appearance.spacing.normal + z: 1 + + CustomRect { + color: Recorder.running ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer + implicitHeight: { + const h = icon.implicitHeight + Appearance.padding.smaller * 2; + return h - (h % 2); + } + implicitWidth: implicitHeight + radius: Appearance.rounding.full + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -0.5 + anchors.verticalCenterOffset: 1.5 + color: Recorder.running ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + text: "screen_record" + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + CustomText { + Layout.fillWidth: true + elide: Text.ElideRight + font.pointSize: Appearance.font.size.normal + text: qsTr("Screen Recorder") + } + + CustomText { + Layout.fillWidth: true + color: DynamicColors.palette.m3onSurfaceVariant + elide: Text.ElideRight + font.pointSize: Appearance.font.size.small + text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off") + } + } + + CustomSplitButton { + active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0] + disabled: Recorder.running + + menuItems: [ + MenuItem { + activeText: qsTr("Fullscreen") + icon: "fullscreen" + text: qsTr("Record fullscreen") + + onClicked: Recorder.start() + }, + MenuItem { + activeText: qsTr("Region") + icon: "screenshot_region" + text: qsTr("Record region") + + onClicked: Recorder.start(["-r"]) + }, + MenuItem { + activeText: qsTr("Fullscreen") + icon: "select_to_speak" + text: qsTr("Record fullscreen with sound") + + onClicked: Recorder.start(["-s"]) + }, + MenuItem { + activeText: qsTr("Region") + icon: "volume_up" + text: qsTr("Record region with sound") + + onClicked: Recorder.start(["-s", "-r"]) + } + ] + + menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text + } + } + + Loader { + id: listOrControls + + property bool running: Recorder.running + + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + asynchronous: true + sourceComponent: running ? recordingControls : recordingList + + Behavior on Layout.preferredHeight { + id: locHeightAnim + + enabled: false + + Anim { + } + } + Behavior on running { + SequentialAnimation { + ParallelAnimation { + Anim { + duration: Appearance.anim.durations.small + easing: Appearance.anim.curves.standardAccel + property: "scale" + target: listOrControls + to: 0.7 + } + + Anim { + duration: Appearance.anim.durations.small + easing: Appearance.anim.curves.standardAccel + property: "opacity" + target: listOrControls + to: 0 + } + } + + PropertyAction { + property: "enabled" + target: locHeightAnim + value: true + } + + PropertyAction { + } + + PropertyAction { + property: "enabled" + target: locHeightAnim + value: false + } + + ParallelAnimation { + Anim { + duration: Appearance.anim.durations.small + easing: Appearance.anim.curves.standardDecel + property: "scale" + target: listOrControls + to: 1 + } + + Anim { + duration: Appearance.anim.durations.small + easing: Appearance.anim.curves.standardDecel + property: "opacity" + target: listOrControls + to: 1 + } + } + } + } + } + } + + Component { + id: recordingList + + RecordingList { + props: root.props + visibilities: root.visibilities + } + } + + Component { + id: recordingControls + + RowLayout { + spacing: Appearance.spacing.normal + + CustomRect { + color: Recorder.paused ? DynamicColors.palette.m3tertiary : DynamicColors.palette.m3error + implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2 + implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2 + radius: Appearance.rounding.full + + Behavior on implicitWidth { + Anim { + } + } + SequentialAnimation on opacity { + alwaysRunToEnd: true + loops: Animation.Infinite + running: !Recorder.paused + + Anim { + duration: Appearance.anim.durations.large + easing: Appearance.anim.curves.emphasizedAccel + from: 1 + to: 0 + } + + Anim { + duration: Appearance.anim.durations.extraLarge + easing: Appearance.anim.curves.emphasizedDecel + from: 0 + to: 1 + } + } + + CustomText { + id: recText + + anchors.centerIn: parent + animate: true + color: Recorder.paused ? DynamicColors.palette.m3onTertiary : DynamicColors.palette.m3onError + font.family: Appearance.font.family.mono + text: Recorder.paused ? "PAUSED" : "REC" + } + } + + CustomText { + font.pointSize: Appearance.font.size.normal + text: { + const elapsed = Recorder.elapsed; + + const hours = Math.floor(elapsed / 3600); + const mins = Math.floor((elapsed % 3600) / 60); + const secs = Math.floor(elapsed % 60).toString().padStart(2, "0"); + + let time; + if (hours > 0) + time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`; + else + time = `${mins}:${secs}`; + + return qsTr("Recording for %1").arg(time); + } + } + + Item { + Layout.fillWidth: true + } + + IconButton { + checked: Recorder.paused + font.pointSize: Appearance.font.size.large + icon: Recorder.paused ? "play_arrow" : "pause" + label.animate: true + toggle: true + type: IconButton.Tonal + + onClicked: { + Recorder.togglePause(); + internalChecked = Recorder.paused; + } + } + + IconButton { + font.pointSize: Appearance.font.size.large + icon: "stop" + inactiveColour: DynamicColors.palette.m3error + inactiveOnColour: DynamicColors.palette.m3onError + + onClicked: Recorder.stop() + } + } + } +} diff --git a/Modules/Notifications/Sidebar/Utils/Cards/RecordingList.qml b/Modules/Notifications/Sidebar/Utils/Cards/RecordingList.qml new file mode 100644 index 0000000..bb94fc9 --- /dev/null +++ b/Modules/Notifications/Sidebar/Utils/Cards/RecordingList.qml @@ -0,0 +1,226 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import ZShell.Models +import qs.Components +import qs.Helpers +import qs.Paths +import qs.Config + +ColumnLayout { + id: root + + required property var props + required property PersistentProperties visibilities + + spacing: 0 + + WrapperMouseArea { + Layout.fillWidth: true + cursorShape: Qt.PointingHandCursor + + onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded + + RowLayout { + spacing: Appearance.spacing.smaller + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pointSize: Appearance.font.size.large + text: "list" + } + + CustomText { + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + font.pointSize: Appearance.font.size.normal + text: qsTr("Recordings") + } + + IconButton { + icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more" + label.animate: true + type: IconButton.Text + + onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded + } + } + } + + CustomListView { + id: list + + Layout.fillWidth: true + Layout.rightMargin: -Appearance.spacing.small + clip: true + implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3) + + CustomScrollBar.vertical: CustomScrollBar { + flickable: list + } + add: Transition { + Anim { + from: 0 + property: "opacity" + to: 1 + } + + Anim { + from: 0.5 + property: "scale" + to: 1 + } + } + delegate: RowLayout { + id: recording + + property string baseName + required property FileSystemEntry modelData + + anchors.left: list.contentItem.left + anchors.right: list.contentItem.right + anchors.rightMargin: Appearance.spacing.small + spacing: Appearance.spacing.small / 2 + + Component.onCompleted: baseName = modelData.baseName + + CustomText { + Layout.fillWidth: true + Layout.rightMargin: Appearance.spacing.small / 2 + color: DynamicColors.palette.m3onSurfaceVariant + elide: Text.ElideRight + text: { + const time = recording.baseName; + const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/); + if (!matches) + return time; + const date = new Date(...matches.slice(1)); + date.setMonth(date.getMonth() - 1); + return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale())); + } + } + + IconButton { + icon: "play_arrow" + type: IconButton.Text + + onClicked: { + root.visibilities.sidebar = false; + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]); + } + } + + IconButton { + icon: "folder" + type: IconButton.Text + + onClicked: { + root.visibilities.sidebar = false; + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]); + } + } + } + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + + Anim { + property: "y" + } + } + Behavior on implicitHeight { + Anim { + } + } + model: FileSystemModel { + nameFilters: ["recording_*.mp4"] + path: Paths.recsdir + sortReverse: true + } + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + + Anim { + property: "scale" + to: 0.5 + } + } + + Loader { + active: opacity > 0 + anchors.centerIn: parent + asynchronous: true + opacity: list.count === 0 ? 1 : 0 + + Behavior on opacity { + Anim { + } + } + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.small + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0 + color: DynamicColors.palette.m3outline + font.pointSize: Appearance.font.size.extraLarge + opacity: root.props.recordingListExpanded ? 1 : 0 + scale: root.props.recordingListExpanded ? 1 : 0 + text: "scan_delete" + + Behavior on Layout.preferredHeight { + Anim { + } + } + Behavior on opacity { + Anim { + } + } + Behavior on scale { + Anim { + } + } + } + + RowLayout { + spacing: Appearance.spacing.smaller + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0 + color: DynamicColors.palette.m3outline + opacity: !root.props.recordingListExpanded ? 1 : 0 + scale: !root.props.recordingListExpanded ? 1 : 0 + text: "scan_delete" + + Behavior on Layout.preferredWidth { + Anim { + } + } + Behavior on opacity { + Anim { + } + } + Behavior on scale { + Anim { + } + } + } + + CustomText { + color: DynamicColors.palette.m3outline + text: qsTr("No recordings found") + } + } + } + } + } +} diff --git a/Modules/Notifications/Sidebar/Utils/Content.qml b/Modules/Notifications/Sidebar/Utils/Content.qml index d9404ea..348340a 100644 --- a/Modules/Notifications/Sidebar/Utils/Content.qml +++ b/Modules/Notifications/Sidebar/Utils/Content.qml @@ -1,13 +1,14 @@ -import qs.Modules.Notifications.Sidebar.Utils.Cards -import qs.Config +import Quickshell import QtQuick import QtQuick.Layouts +import qs.Modules.Notifications.Sidebar.Utils.Cards +import qs.Config Item { id: root required property Item popouts - required property var props + required property PersistentProperties props required property var visibilities implicitHeight: layout.implicitHeight @@ -22,6 +23,12 @@ Item { IdleInhibit { } + Record { + props: root.props + visibilities: root.visibilities + z: 1 + } + Toggles { popouts: root.popouts visibilities: root.visibilities diff --git a/cli/pyproject.toml b/cli/pyproject.toml index a234745..d7e1888 100644 --- a/cli/pyproject.toml +++ b/cli/pyproject.toml @@ -9,6 +9,7 @@ version = "0.1.0" dependencies = [ "typer", "pillow", + "jinja2", "materialyoucolor" ] diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc index 71fa4f894106bca816f890854e4b585d2df759bb..7e9924e359f43ab124a1f7be44fc065360606053 100644 GIT binary patch literal 24035 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 delta 3527 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 diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc index 043fc1df55b2e6a5d932ad16cb9504f6c6f86496..307d7075fdd6fe85f74a972e7066a81f0e6578cf 100644 GIT binary patch delta 151 zcmcb_ew3Z}GcPX}0}!|`;mvZ`$a{~GQG4EB6mYkeE|oErFp}^ zjM`96KlJ4qja=5Mp%*)Hg00cUBr)9D;Z{$0`#%MYDJe!i#4H2mc79W`zMPzQsX@Y328-}Kz znHgElCo{A6Fus^Pf&Hj96QlVA;SUTzYDO}c+Q70Qcq8W*kjQ6d1}6TGOh8rtD8AEV0TOlDP1reH>^2nL2k;mPZnCCwRwnM|2LCNeN6Fr+ht zvIH}-0@=aLRzeI6DVz)-5f-orD@Y_!A1J~c#5q}*MOhLe&ZZ00Z^9G}HUmTiaZUcn ztY{0=iw@wXvxD@&O$PHYOps9mTEvTP1Or1fA51JrU}AyD<)vg(f6kW*5J~!QIc%$uU8CM(Py~l^Yy<57@ao92?6gh&0#D5SfuUQ+$ERY`M+5 zSe+T`85xrpCzyO@0MVbB8JPG#FoBpKI2f2%+oc<&n`J+UFi1#!6qaCAydfxcgM;S= z2X8-57f(0e2WCc2iI2?8LTn$HfwCXC7=)y8$a90_g&2fHzktjE+w+kL$SPtH2D%;q DRH<)U delta 463 zcmZ{ey-Nad7{`CFdD@*Xb$W=_bzq2uwHQ(%MTIRQl{861P=pX=N)0U)4ZS#Y@{2NB z8f$2X_8g=C;P8)#ldGYrem@~<>AO6i=lMQwP2Yh}aTLV^xLz}trK?Bf5y45;M3K0q z>Sm^mp=wyM#BEy8kTsmXD+(I3re+-sX%?~%G>tAGdxkN#j0X);fRt}5pz$66R^0$B zkpk{ih^VZLuo@1tH!K-6iT=2qEQN~Vm5vrArV)dgSmoV*h}jp`pu~2Fu6O_R{KlgE z!;9W}S!FLog8^2@!JuoDpAi}W>mVWJD` zU7S{S*VqP~=<4Nm^`1RYU6tgMg;SRqt9cu-#`bmmcJ^lY>66aDeFU@6OgTVA2Lt4@ zkwDu65Iv3@MvnSy6-4{ny(%=UV812%Eje(WJImGbHik;Hjd93hWA5^ikp7R~E&Lu3 Q3crgzojYyBsY1k)-vC@`SpWb4 diff --git a/cli/src/zshell/subcommands/record.py b/cli/src/zshell/subcommands/record.py index f0ef76b..32b94fd 100644 --- a/cli/src/zshell/subcommands/record.py +++ b/cli/src/zshell/subcommands/record.py @@ -3,7 +3,6 @@ import os import json import subprocess import time -import signal from pathlib import Path from typing import Optional @@ -15,19 +14,15 @@ RECORDER = "gpu-screen-recorder" HOME = str(os.getenv("HOME", str(Path.home()))) CONFIG = Path(HOME) / ".config/zshell/config.json" -# Paths for temp recording and notifications STATE_DIR = Path(HOME) / ".local/state/zshell/record" TEMP_RECORDING = STATE_DIR / "recording.mp4" NOTIF_ID_FILE = STATE_DIR / "notifid.txt" -# Where final recordings are saved RECORDINGS_DIR = os.getenv("ZSHELL_RECORDINGS_DIR", str(Path(HOME) / "Videos/Recordings")) -# ── helpers ────────────────────────────────────────────── def _read_extra_args() -> list[str]: - """Return extra gpu-screen-recorder arguments from the user config.""" try: if CONFIG.is_file(): data = json.loads(CONFIG.read_text()) @@ -38,12 +33,10 @@ def _read_extra_args() -> list[str]: def _is_recording() -> bool: - """Check if gpu-screen-recorder process exists.""" return subprocess.run(["pidof", RECORDER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0 -def _notify(summary: str, body: str = "", actions: list = None, timeout: int = 3000) -> Optional[int]: - """Send a desktop notification. Returns the notification ID or None.""" +def _notify(summary: str, body: str = "", actions: list = None, timeout: int = 5000) -> Optional[int]: args = ["notify-send", summary, body, "-t", str(timeout), "-p"] if actions: for action in actions: @@ -56,13 +49,11 @@ def _notify(summary: str, body: str = "", actions: list = None, timeout: int = 3 def _close_notification(notif_id: int): - """Close a notification by its ID.""" subprocess.run(["notify-send", "--close", str(notif_id)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def _get_monitors() -> list[dict]: - """Get monitor info from Hyprland.""" try: res = subprocess.run(["hyprctl", "monitors", "-j"], capture_output=True, text=True) @@ -72,16 +63,13 @@ def _get_monitors() -> list[dict]: def _focused_monitor_name() -> Optional[str]: - """Return name of the currently focused monitor.""" - monitors = _get_monitors() - for m in monitors: + for m in _get_monitors(): if m.get("focused"): return m["name"] return None def _monitors_intersecting_region(x: int, y: int, w: int, h: int) -> list[dict]: - """Return monitors whose area intersects the given region.""" region = (x, y, x + w, y + h) intersecting = [] for m in _get_monitors(): @@ -92,12 +80,10 @@ def _monitors_intersecting_region(x: int, y: int, w: int, h: int) -> list[dict]: def _highest_refresh(monitors: list[dict]) -> float: - """Return the maximum refresh rate among the given monitors.""" return max((m["refreshRate"] for m in monitors), default=60.0) def _slurp_region() -> Optional[str]: - """Call slurp and return geometry like 'WxH+X+Y'.""" try: return subprocess.check_output(["slurp", "-f", "%wx%h+%x+%y"], text=True).strip() except subprocess.CalledProcessError: @@ -105,7 +91,6 @@ def _slurp_region() -> Optional[str]: def _parse_geometry(geometry: str) -> Optional[tuple[int, int, int, int]]: - """Parse 'WxH+X+Y' into (x,y,w,h).""" import re match = re.match(r"(\d+)x(\d+)\+(\d+)\+(\d+)", geometry) if match: @@ -113,12 +98,9 @@ def _parse_geometry(geometry: str) -> Optional[tuple[int, int, int, int]]: return None -# ── core actions ───────────────────────────────────────── def start_recording(region: Optional[str], sound: bool): - """Launch gpu-screen-recorder.""" STATE_DIR.mkdir(parents=True, exist_ok=True) - - cmd = [RECORDER, "-w"] # -w for window/display + cmd = [RECORDER] extra_args = _read_extra_args() if region: @@ -129,43 +111,41 @@ def start_recording(region: Optional[str], sound: bool): raise typer.Abort() else: geometry = region + parsed = _parse_geometry(geometry) - if parsed: - x, y, w, h = parsed - monitors = _monitors_intersecting_region(x, y, w, h) - framerate = _highest_refresh(monitors) - cmd.extend(["-region", geometry, "-f", str(int(framerate))]) - else: + if not parsed: typer.echo("Invalid geometry format.") raise typer.Abort() + x, y, w, h = parsed + + monitors = _monitors_intersecting_region(x, y, w, h) + framerate = _highest_refresh(monitors) + cmd.extend(["-w", "-region", geometry, "-f", str(int(framerate))]) + else: - # Fullscreen: use focused monitor - monitor = _focused_monitor_name() - if monitor: - cmd.extend(["-m", monitor]) - # Refresh rate comes from that monitor - monitors = _get_monitors() - mon = next((m for m in monitors if m["name"] == monitor), None) - if mon: - cmd.extend(["-f", str(int(mon["refreshRate"]))]) + monitor_name = _focused_monitor_name() + if not monitor_name: + typer.echo("No focused monitor found.") + raise typer.Abort() + + monitors = _get_monitors() + mon = next((m for m in monitors if m["name"] == monitor_name), None) + rate = int(mon["refreshRate"]) if mon else 60 + cmd.extend(["-w", monitor_name, "-f", str(rate)]) if sound: - cmd.append("-a") - cmd.append("default_output") + cmd.extend(["-a", "default_output"]) cmd.extend(extra_args) - cmd.append(str(TEMP_RECORDING)) + cmd.extend(["-o", str(TEMP_RECORDING)]) - # Launch detached subprocess.Popen(cmd, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - # Notification notif_id = _notify("Recording started", f"Saving to {TEMP_RECORDING}") if notif_id is not None: NOTIF_ID_FILE.write_text(str(notif_id)) - # Early failure check time.sleep(1) if not _is_recording(): _notify("Recording failed", @@ -174,26 +154,22 @@ def start_recording(region: Optional[str], sound: bool): def stop_recording(clipboard: bool): - """Stop the recording and finalise the file.""" - # Kill the process subprocess.run(["pkill", "-f", RECORDER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - # Wait until it really stops - for _ in range(50): # 5 seconds max + for _ in range(50): if not _is_recording(): break time.sleep(0.1) - # Move the recording dest_dir = Path(RECORDINGS_DIR) dest_dir.mkdir(parents=True, exist_ok=True) timestamp = time.strftime("%Y-%m-%d_%H-%M-%S") final_path = dest_dir / f"recording_{timestamp}.mp4" + if TEMP_RECORDING.exists(): TEMP_RECORDING.rename(final_path) - # Close the start notification if NOTIF_ID_FILE.is_file(): try: _close_notification(int(NOTIF_ID_FILE.read_text().strip())) @@ -201,23 +177,19 @@ def stop_recording(clipboard: bool): pass NOTIF_ID_FILE.unlink() - # Clipboard if clipboard: subprocess.run(["wl-copy", "--type", "text/uri-list", f"file://{final_path}"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - # Final notification (simplified: no actions) _notify("Recording stopped", f"Saved to {final_path}", timeout=5000) def toggle_pause(): - """Send SIGUSR2 to gpu-screen-recorder.""" subprocess.run(["pkill", "-USR2", "-f", RECORDER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) typer.echo("Toggled pause.") -# ── Typer command ──────────────────────────────────────── @app.command() def record( region: Optional[str] = typer.Option( @@ -231,10 +203,7 @@ def record( clipboard: bool = typer.Option( False, "--clipboard", "-c", help="Copy the final recording path to clipboard."), ): - """ - Start or stop a screen recording with gpu-screen-recorder. - Running again stops the current recording. - """ + """Start or stop a screen recording with gpu-screen-recorder.""" if pause: toggle_pause() raise typer.Exit() diff --git a/cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc b/cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc index 4f3c04b2c71eaf549300244b60f0c8436376b824..61bbb4752ce20bfa3ccccc775f31196b894f6cfa 100644 GIT binary patch delta 21 bcmaFE^@fY*GcPX}0}%8q Date: Fri, 22 May 2026 20:42:51 +0200 Subject: [PATCH 04/11] prep for replay --- cli/src/zshell/subcommands/record.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/zshell/subcommands/record.py b/cli/src/zshell/subcommands/record.py index 32b94fd..f568137 100644 --- a/cli/src/zshell/subcommands/record.py +++ b/cli/src/zshell/subcommands/record.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import json import subprocess @@ -16,6 +15,7 @@ CONFIG = Path(HOME) / ".config/zshell/config.json" STATE_DIR = Path(HOME) / ".local/state/zshell/record" TEMP_RECORDING = STATE_DIR / "recording.mp4" +REPLAY_RECORDING = STATE_DIR / "replay.mp4" NOTIF_ID_FILE = STATE_DIR / "notifid.txt" RECORDINGS_DIR = os.getenv("ZSHELL_RECORDINGS_DIR", From d0cda51639389dd139403629695a2776d3bc80f5 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sat, 23 May 2026 20:31:48 +0200 Subject: [PATCH 05/11] wait for instance to fully terminate before restart --- .../__pycache__/scheme.cpython-314.pyc | Bin 30628 -> 30628 bytes .../__pycache__/shell.cpython-314.pyc | Bin 3233 -> 3592 bytes cli/src/zshell/subcommands/shell.py | 8 +++++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc index 010ddf9aca33ee16104f3c05a33b7ea086c845dd..e5535703c5f0e815418b2501a20b9cf701d2044c 100644 GIT binary patch delta 21 bcmZ4To^i>0MlNkWUM>b8SoD4)*Q{~?O>+j| delta 21 bcmZ4To^i>0MlNkWUM>b8$U3!=YgRb`OKJv# diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc index a47f91f92d18495fe005df7c52d64cec7377d725..7f6e76463bf6cf7365accb2eab566883d2689ae9 100644 GIT binary patch delta 1001 zcmZ8fO-vI(6rQ&~-R*9FSOcY$mLjFqEl_@f(SVVtk@$-M^xy%6#G5*^ZI$?v`DW&OZ{Bc7721IxHLL%T1mD25isFr!ny~mHI#D)YKFGQB$5cr4u;*LF3HOw58#YGQ1T{}}ie!=2ZhHtExe;mHxx7Od;zW*4pTm}%y8-YLEfL$(W>`NEi$ zXJt#&*B3h>QPSx}jIxz<<)_FhS9Lc2UTE9&?wjp+aCHVYwc1B@^L0zYGuPtOvVTQb z(@xE}KC0Tf8eUbyi~O1z`{dC!WzR$9o-*6{K@M)ak*|7JL86~zg$9ywE&3DGJ7y4N zVIpKj4ijBk@E>G6gGR;&C|^mwNXrl>cjYFfiD?<=lG!_gI{fNecZ=_4+XD zKK*J7<5LV;DHMO2D9)T??m&usRt9B%v64~Jqb3{KAYxVlCqE|{C#EeQ$D@UDbHc(& za$k)EyQmGDuKYI&TRZ@4AZ-Jw(w(szW^KWqg?c}?vYiy276gzHJl7#2xAA_65 Ak^lez delta 691 zcmYk3&ubGw6vyZ7&i?)pgV82w<7yJuY%8@ws~3q>LGZGMZH`7GrHE}6oLxbXLJ`DX zDy%O;K@h}?Ud5A#B7%Q|P_OpjEkVJnGrOrehtItCo%eX(nc13pU2$hz$0U4h>>gTu zFQ;y~{s9QtBsWL|S4ooZkiaa7>}!xnJ?N---zd5BqKmJD_GrgSUrnalwxZ_oSw+i( zS~@Bz`naH|O_0A`#(}8+Cz@jsH^5dbk>E3!l%Z1=Bk>cQaGVGlByfL-(IKY#no8I1 ztgmG_e=k}e-jBp7-bwJ`Oa*9z6>~o5`4tIv52dRgMDinWbCVrWjYI|dBwqslt?-+ z<(Wq!mAlp$<@pt+aIy)3GDkOLnuseLF@JmFGlz3eV=HlTizTeav%}(W0WWA(iMsew z`&>BA6(*4N)zCAia7!PUb)gF!L*Lj15BH53^P~_38dx<)5TI@SYI{O#a&$9Cxs5<( zr-a@T2smPy!}oJjS$T#Qw(XwmG9BO8(@pV+na|8oHa;7-r!TVG5ALqqOIQ;}cI}Ax qe{sinpJONkz&BDv->F-3KV>2nh7!OWE;&I_e85-|;n2iw=g}W)m4*ZW diff --git a/cli/src/zshell/subcommands/shell.py b/cli/src/zshell/subcommands/shell.py index c6a8587..ae73d0b 100644 --- a/cli/src/zshell/subcommands/shell.py +++ b/cli/src/zshell/subcommands/shell.py @@ -1,4 +1,5 @@ import subprocess +import time import typer args = ["qs", "-c", "zshell"] @@ -8,7 +9,7 @@ app = typer.Typer() @app.command() def kill(): - subprocess.run(args + ["kill"], check=True) + subprocess.run(args + ["kill"], check=False) @app.command() @@ -19,6 +20,11 @@ def start(no_daemon: bool = False): @app.command() def restart(no_daemon: bool = False): subprocess.run(args + ["kill"], check=False) + for _ in range(50): + result = subprocess.run(args + ["kill"], capture_output=True) + if result.returncode == 255: + break + time.sleep(0.05) subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True) From b49165e7eac336d6edfde36bd1ef92fbd1797186 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sat, 23 May 2026 20:48:51 +0200 Subject: [PATCH 06/11] minor typer adjustments to use typer in error/exception throws --- .../__pycache__/shell.cpython-314.pyc | Bin 3592 -> 6639 bytes cli/src/zshell/subcommands/shell.py | 44 ++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc index 7f6e76463bf6cf7365accb2eab566883d2689ae9..a33767152f267077925eaebafc8768711f2566be 100644 GIT binary patch literal 6639 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 literal 3592 zcmcH*TWl0n^xm1-cONW8icl!ErLaPG5Gx=c2+^uBEbCYcCZ+2#JKe53yR+PxjfD?W z!35%m64SS&*x1l~S*mk{buj<$V9_a<&FnAm*LC`H!qg#`LJ5i+RHe-pY4BOy= zi3s0f4A2-FwD(b5aHh_r0}a~IfD{zPI~)oE85Chpue6%gE1VEK@$)b1F%CPFu37 zXJnJ8@>z34({&l{QH@+KnNOKA--#B^5GEc+ES}A^fX2`-QqzUlx!8E`8HOIg)H`gDT+%Yx?T-)^?zAD1Napi~m9(@(f;cY_fRBS0Fb|DUxbA+;zBES$ne{jf?XvTC73zy4 zRB(mbJ?EjQNVeMw!oafCc<9f)C+yH}M@QEW^6Jk-iL<<@0jMt?TfTPmqJmHWZMv6A z;awV7%LbosDUTv9sV061z5vhbJ|21fkYY`0vS1a7mN1G|p=hN)`jElQA<_!+lXZY% z5g%c_hy)m7I#Lfw=F=Jt5)F>#RU@TQ$;#w3>M?aqD?~&d%M>T5muO~Dw@l{v?#-La zf$f7$9@?F-%L8l_ChpL#l$beb=dH%omv+7T>P37jyy1gQ?{E54n)XhOe%5?Nx*mS^ zqW4B9Tne>)8)};puZKE+Xb9i(H@p{oCwQs%d;hwH0BUOeEr>kLmC98oV?Y20oB}Zf zTlW{KHU3zp7*H`&P^n~&7;m`i0SUo>^CaRnBi(GtP&<6)MnGxsV&mN4cD=ClB+UJdDR%=K1PlwLD&yF2DR`fc5F&O2c3Z z+TcX&6zn`m&kxi*x&~@`cE7M6+nqfP6173nMbVOH+A@jEV}mfI-9Z7hum`qClp$^w zreb$@xyN&Mju_qC2k76$$dzoV@Ax(Ny>fi6<;1nuQYA^_Arld)aN0a8^r+NZe&R)N zU!=KQ!CCE~9_vg&Bb7ql&*oH277El?c?XtXf9%ykIvL`XhvzQ~Vd_6j(#4#Xx5~1I z7z=B6<&6D z1kZ&HZ*4fgaY4ZNu|*LH>$F?{_G7VI9K`DTbHO*ps6|W7GLH&N+7DKIhmz*C|Gk o9g18-iQD&K9C!cMjRS|jiG3Bj+WXys_+1{k{E9npStW@70&SWktpET3 diff --git a/cli/src/zshell/subcommands/shell.py b/cli/src/zshell/subcommands/shell.py index ae73d0b..d66ea57 100644 --- a/cli/src/zshell/subcommands/shell.py +++ b/cli/src/zshell/subcommands/shell.py @@ -1,5 +1,8 @@ import subprocess +import sys import time + +import click import typer args = ["qs", "-c", "zshell"] @@ -9,40 +12,65 @@ app = typer.Typer() @app.command() def kill(): - subprocess.run(args + ["kill"], check=False) + result = subprocess.run(args + ["kill"], capture_output=True) + if result.returncode != 0: + raise click.ClickException("No running instance to kill.") + sys.stderr.write(result.stderr.decode()) @app.command() def start(no_daemon: bool = False): - subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True) + check = subprocess.run(args + ["ipc"] + ["show"], capture_output=True) + if check.returncode == 0: + raise click.ClickException("An instance of this configuration is already running.") + result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stderr.write(result.stderr.decode()) @app.command() def restart(no_daemon: bool = False): - subprocess.run(args + ["kill"], check=False) + subprocess.run(args + ["kill"]) for _ in range(50): result = subprocess.run(args + ["kill"], capture_output=True) if result.returncode == 255: break time.sleep(0.05) - subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True) + result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stderr.write(result.stderr.decode()) @app.command() def show(): - subprocess.run(args + ["ipc"] + ["show"], check=True) + result = subprocess.run(args + ["ipc"] + ["show"], capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stderr.write(result.stderr.decode()) @app.command() def log(): - subprocess.run(args + ["log"], check=True) + result = subprocess.run(args + ["log"], capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stdout.write(result.stdout.decode()) + sys.stderr.write(result.stderr.decode()) @app.command() def lock(): - subprocess.run(args + ["ipc"] + ["call"] + ["lock"] + ["lock"], check=True) + result = subprocess.run(args + ["ipc"] + ["call"] + ["lock"] + ["lock"], capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stderr.write(result.stderr.decode()) @app.command() def call(target: str, method: str, method_args: list[str] = typer.Argument(None)): - subprocess.run(args + ["ipc"] + ["call"] + [target] + [method] + (method_args or []), check=True) + result = subprocess.run(args + ["ipc"] + ["call"] + [target] + [method] + (method_args or []), capture_output=True) + if result.returncode != 0: + raise click.ClickException(result.stderr.decode().strip()) + sys.stderr.write(result.stderr.decode()) From 5e9b3734059e7bafc9d3125f6178e072f8184c81 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sat, 23 May 2026 20:54:35 +0200 Subject: [PATCH 07/11] tests did not match changed code logic --- cli/tests/test_shell.py | 82 ++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/cli/tests/test_shell.py b/cli/tests/test_shell.py index feb292c..9875d99 100644 --- a/cli/tests/test_shell.py +++ b/cli/tests/test_shell.py @@ -1,13 +1,15 @@ from __future__ import annotations +from subprocess import CompletedProcess from unittest.mock import patch, call + +from typer.testing import CliRunner from zshell.subcommands.shell import app +runner = CliRunner() -def invoke(*args: str) -> None: - from typer.testing import CliRunner - runner = CliRunner() +def invoke(*args: str): result = runner.invoke(app, args) if result.exit_code != 0: raise RuntimeError(result.output) @@ -16,72 +18,118 @@ def invoke(*args: str) -> None: class TestKill: @patch("zshell.subcommands.shell.subprocess.run") - def test_kill_runs_qs_kill(self, mock_run): + def test_kill_runs_qs_kill_success(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"Killed abc\n") invoke("kill") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "kill"], check=True) + mock_run.assert_called_once_with(["qs", "-c", "zshell", "kill"], capture_output=True) + + @patch("zshell.subcommands.shell.subprocess.run") + def test_kill_no_instance_errors(self, mock_run): + mock_run.return_value = CompletedProcess([], 255, b"", b"No running instances\n") + result = runner.invoke(app, ["kill"]) + assert result.exit_code != 0 + assert "No running instance to kill" in result.output class TestStart: @patch("zshell.subcommands.shell.subprocess.run") def test_start_default_daemon(self, mock_run): + mock_run.side_effect = [ + CompletedProcess([], 1, b"", b""), # ipc show → no instance + CompletedProcess([], 0, b"", b"Launching config\n"), # launch ok + ] invoke("start") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n", "-d"], check=True) + assert mock_run.call_args_list == [ + call(["qs", "-c", "zshell", "ipc", "show"], capture_output=True), + call(["qs", "-c", "zshell", "-n", "-d"], capture_output=True), + ] @patch("zshell.subcommands.shell.subprocess.run") def test_start_no_daemon(self, mock_run): + mock_run.side_effect = [ + CompletedProcess([], 1, b"", b""), + CompletedProcess([], 0, b"", b"Launching config\n"), + ] invoke("start", "--no-daemon") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n"], check=True) + assert mock_run.call_args_list == [ + call(["qs", "-c", "zshell", "ipc", "show"], capture_output=True), + call(["qs", "-c", "zshell", "-n"], capture_output=True), + ] + + @patch("zshell.subcommands.shell.subprocess.run") + def test_start_already_running_errors(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"target visibilities\n") + result = runner.invoke(app, ["start"]) + assert result.exit_code != 0 + assert "already running" in result.output class TestShow: @patch("zshell.subcommands.shell.subprocess.run") def test_show_runs_ipc_show(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"target visibilities\n") invoke("show") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "show"], check=True) + mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "show"], capture_output=True) class TestLog: @patch("zshell.subcommands.shell.subprocess.run") def test_log_runs_qs_log(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"log output\n", b"") invoke("log") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "log"], check=True) + mock_run.assert_called_once_with(["qs", "-c", "zshell", "log"], capture_output=True) class TestLock: @patch("zshell.subcommands.shell.subprocess.run") def test_lock_runs_ipc_call_lock(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"") invoke("lock") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "lock", "lock"], check=True) + mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "lock", "lock"], capture_output=True) class TestCall: @patch("zshell.subcommands.shell.subprocess.run") def test_call_no_args(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"") invoke("call", "target", "method") - mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "target", "method"], check=True) + mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "target", "method"], capture_output=True) @patch("zshell.subcommands.shell.subprocess.run") def test_call_with_args(self, mock_run): + mock_run.return_value = CompletedProcess([], 0, b"", b"") invoke("call", "target", "method", "arg1", "arg2") mock_run.assert_called_once_with( ["qs", "-c", "zshell", "ipc", "call", "target", "method", "arg1", "arg2"], - check=True, + capture_output=True, ) class TestRestart: @patch("zshell.subcommands.shell.subprocess.run") - def test_restart_kills_then_starts_daemon(self, mock_run): + def test_restart_kills_then_starts(self, mock_run): + mock_run.side_effect = [ + CompletedProcess([], 0, b"", b"Killed abc\n"), # first kill (no capture) + CompletedProcess([], 255, b"", b""), # poll → no instance + CompletedProcess([], 0, b"", b"Launching config\n"), # launch ok + ] invoke("restart") assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "kill"], check=False), - call(["qs", "-c", "zshell", "-n", "-d"], check=True), + call(["qs", "-c", "zshell", "kill"]), # no capture_output + call(["qs", "-c", "zshell", "kill"], capture_output=True), + call(["qs", "-c", "zshell", "-n", "-d"], capture_output=True), ] @patch("zshell.subcommands.shell.subprocess.run") def test_restart_no_daemon(self, mock_run): + mock_run.side_effect = [ + CompletedProcess([], 0, b"", b"Killed abc\n"), + CompletedProcess([], 255, b"", b""), + CompletedProcess([], 0, b"", b"Launching config\n"), + ] invoke("restart", "--no-daemon") assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "kill"], check=False), - call(["qs", "-c", "zshell", "-n"], check=True), + call(["qs", "-c", "zshell", "kill"]), + call(["qs", "-c", "zshell", "kill"], capture_output=True), + call(["qs", "-c", "zshell", "-n"], capture_output=True), ] From 78fcf33b3a77003e102401acedf5e40f4ba69f62 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sun, 24 May 2026 03:09:19 +0200 Subject: [PATCH 08/11] refactor(cli): clean shell start/restart, drop redundant ipc check --- .../__pycache__/scheme.cpython-314.pyc | Bin 30628 -> 30626 bytes .../__pycache__/screenshot.cpython-314.pyc | Bin 1042 -> 1040 bytes .../__pycache__/shell.cpython-314.pyc | Bin 6639 -> 6472 bytes .../__pycache__/wallpaper.cpython-314.pyc | Bin 2438 -> 2436 bytes cli/src/zshell/subcommands/shell.py | 29 ++++++----- cli/tests/test_shell.py | 47 ++++++++---------- 6 files changed, 37 insertions(+), 39 deletions(-) diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc index e5535703c5f0e815418b2501a20b9cf701d2044c..06584ac0875cc72ca33cd0db9527c59ae4813dbb 100644 GIT binary patch delta 39 tcmZ4To^jE8Ms96BUM>b8P<9vE$gRi1ZL6P=pPQ0Ms96BUM>b8SoB_SBexz4uf2Xoer~FMc7A1kZsukembhX71CR{K diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc index ecd3450d69ddad48296ea32af8832e861aa929c1..f1921ea0037d724a68c84ccba54f287a3d7a389b 100644 GIT binary patch delta 37 rcmbQlF@b|yn~#@^0SJ`cg*I}}W8`+!&&bbB)lV!+%-y_=F@^~Mjt~hU delta 39 tcmbQhF^Pj)n~#@^0SNN832fw^$H?ofpOK%Ns-K--nV*}vc?)9<69BdD3eo@o diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc index a33767152f267077925eaebafc8768711f2566be..d6ca5095d3c790b30885eb76e34adb694c63a97e 100644 GIT binary patch delta 1671 zcmZ8h&u<$=6rNeH?akV|o3)+TiR~n=W5-TNoY17W6chrYqExt%Rar$OR8ed-M$X#I zZm8%Xb<3ep1gV*#h98F@kZ2`@it;BQpXu!EhXMy_T;?UAS2p7`4lXuwk9$sVaLaBq^trw8e|kycZSP z3%GJKgq08QgrubHU=>a;q1M^nE-iryX82&a%TWl*+9hewLr^qo*Vf z-N2IH38$sj>HAS?8i!H5ef=K(9y^{&EEE@Wi8(U2NUvJH7J0~Hfq5rJ|L{aYX-k5G zVE$JQY>hUpcr-hgTP$h~8_5|IzP>XxMpLo`><_S8yc@{YMO)v^+?Ww!-(>PH@8-%(d2dw7G*@Ih44wqy)ygG zY+VXfrBF=@*QIz>ir1u}^8TOg(xxM@X8Y3lne%h`nq#Et^449^tFGwU8#UL+hI3@o zF4gV6s@=CbbF+Wp`cPbyeQAwx=c!ZU}?7 ztw`u0z%C{Hl$~_KeTbJj+Qv>|+;bZNoIh+nSPYuqE)XnRYBCiSfK3_A-1lYBP8E7l z8bK9sDvr%>zJyJ-bQT(IQ3DJEH6#j_KA1XVwv2w^1=qQ~H~1j&&=Nnzkucn;Kft1N z#%N2AF{Z%Sc~ginQ-~S}af<#RigGWSu|c3YrUlkF{X314wtxojj}m?~(7h9w!AYoV z_7G^0Cah0GUIn_dD!G;al1IP+y%Rt$`DSeNrY%6PSe+fc=->iEGs;f(3`$#{pg%hN zue2=uGsiyuh>c5=Bm$;XTzFJ}ypdnbHQJyTi$+n)&zo8UAr^AEl1XCRVv^VpvY_Nb zUdz!}oq^|uAsfr6zYf3%l+UD2r_PVB?pcj}IC**eI-hJR?v>@U%QdBUEqq;xlwW9y z^2*5Bk($`OdgPiIpA$#hy(ks1+OXtH z^9^2KC?0Qh7G1Ls4U%4XH<1`H28aq^*1FXOWRw{hjIBGB3tany@E+z-Xv`Bd{|EZJ zR8>6df2zAUoS^L5cZVaA5rEiL9WgG|t$eBI)HFf!%qzf;^bwePMBf6=W@#97byPx;>p{>?$R-LW7} a*2b3T5qsVzI(tKtU1|B+j|{r|BBDpdh3v9j(ACxh+{{ z%*6R&x-8q8!y+0@@Z0ufUmCw@T;dmF#DGJm4Iz9mCVo+t>6Z9K&wU-lpeMP%dwR~f zzkBXE@ARvl-+R?|O;rfWoj*OVZxq!A`c1Lz2z3?562;x1t|n|cNr*a`bI;Kzk3%Ua z=%Q+|+-H+@0!=hR9dL}ct4^Kl$7sdffcTmi55THW*G8kXa<-Qy6lAPA!01lU5Q%6d zhp&Sqep^|K13GBri8kDDaZIsjitMYT$IOQ9GLk(5!4+Q)t jxo;yv^)AZWHF#=HumJ0D`=20vowI7 None: + result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True) + stdout = result.stdout.decode().strip() + if stdout: + if "already running" in stdout.lower(): + raise click.ClickException(stdout) + if result.returncode != 0: + stderr = result.stderr.decode().strip() + raise click.ClickException(stderr) + + @app.command() def start(no_daemon: bool = False): - check = subprocess.run(args + ["ipc"] + ["show"], capture_output=True) - if check.returncode == 0: - raise click.ClickException("An instance of this configuration is already running.") - result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True) - if result.returncode != 0: - raise click.ClickException(result.stderr.decode().strip()) - sys.stderr.write(result.stderr.decode()) + start_instance(no_daemon) @app.command() def restart(no_daemon: bool = False): - subprocess.run(args + ["kill"]) - for _ in range(50): + subprocess.run(args + ["kill"], capture_output=True) + deadline = time.monotonic() + 2.5 + while time.monotonic() < deadline: result = subprocess.run(args + ["kill"], capture_output=True) if result.returncode == 255: break time.sleep(0.05) - result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True) - if result.returncode != 0: - raise click.ClickException(result.stderr.decode().strip()) - sys.stderr.write(result.stderr.decode()) + start_instance(no_daemon=no_daemon) @app.command() diff --git a/cli/tests/test_shell.py b/cli/tests/test_shell.py index 9875d99..1763247 100644 --- a/cli/tests/test_shell.py +++ b/cli/tests/test_shell.py @@ -34,35 +34,30 @@ class TestKill: class TestStart: @patch("zshell.subcommands.shell.subprocess.run") def test_start_default_daemon(self, mock_run): - mock_run.side_effect = [ - CompletedProcess([], 1, b"", b""), # ipc show → no instance - CompletedProcess([], 0, b"", b"Launching config\n"), # launch ok - ] + mock_run.return_value = CompletedProcess([], 0, b"", b"Launching config\n") invoke("start") - assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "ipc", "show"], capture_output=True), - call(["qs", "-c", "zshell", "-n", "-d"], capture_output=True), - ] + mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n", "-d"], capture_output=True) @patch("zshell.subcommands.shell.subprocess.run") def test_start_no_daemon(self, mock_run): - mock_run.side_effect = [ - CompletedProcess([], 1, b"", b""), - CompletedProcess([], 0, b"", b"Launching config\n"), - ] + mock_run.return_value = CompletedProcess([], 0, b"", b"Launching config\n") invoke("start", "--no-daemon") - assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "ipc", "show"], capture_output=True), - call(["qs", "-c", "zshell", "-n"], capture_output=True), - ] + mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n"], capture_output=True) @patch("zshell.subcommands.shell.subprocess.run") def test_start_already_running_errors(self, mock_run): - mock_run.return_value = CompletedProcess([], 0, b"", b"target visibilities\n") + mock_run.return_value = CompletedProcess([], 0, b"An instance of this configuration is already running.\n", b"") result = runner.invoke(app, ["start"]) assert result.exit_code != 0 assert "already running" in result.output + @patch("zshell.subcommands.shell.subprocess.run") + def test_start_other_failure_errors(self, mock_run): + mock_run.return_value = CompletedProcess([], 1, b"", b"Config error\n") + result = runner.invoke(app, ["start"]) + assert result.exit_code != 0 + assert "Config error" in result.output + class TestShow: @patch("zshell.subcommands.shell.subprocess.run") @@ -106,30 +101,30 @@ class TestCall: class TestRestart: + @patch("zshell.subcommands.shell.start_instance") @patch("zshell.subcommands.shell.subprocess.run") - def test_restart_kills_then_starts(self, mock_run): + def test_restart_kills_then_starts(self, mock_run, mock_start): mock_run.side_effect = [ - CompletedProcess([], 0, b"", b"Killed abc\n"), # first kill (no capture) + CompletedProcess([], 0, b"", b"Killed abc\n"), # first kill (captured) CompletedProcess([], 255, b"", b""), # poll → no instance - CompletedProcess([], 0, b"", b"Launching config\n"), # launch ok ] invoke("restart") assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "kill"]), # no capture_output call(["qs", "-c", "zshell", "kill"], capture_output=True), - call(["qs", "-c", "zshell", "-n", "-d"], capture_output=True), + call(["qs", "-c", "zshell", "kill"], capture_output=True), ] + mock_start.assert_called_once_with(no_daemon=False) + @patch("zshell.subcommands.shell.start_instance") @patch("zshell.subcommands.shell.subprocess.run") - def test_restart_no_daemon(self, mock_run): + def test_restart_no_daemon(self, mock_run, mock_start): mock_run.side_effect = [ CompletedProcess([], 0, b"", b"Killed abc\n"), CompletedProcess([], 255, b"", b""), - CompletedProcess([], 0, b"", b"Launching config\n"), ] invoke("restart", "--no-daemon") assert mock_run.call_args_list == [ - call(["qs", "-c", "zshell", "kill"]), call(["qs", "-c", "zshell", "kill"], capture_output=True), - call(["qs", "-c", "zshell", "-n"], capture_output=True), + call(["qs", "-c", "zshell", "kill"], capture_output=True), ] + mock_start.assert_called_once_with(no_daemon=True) From c30128cf95befc11a5deafa77b6c209f0bf56689 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sun, 24 May 2026 18:03:32 +0200 Subject: [PATCH 09/11] check every 50ms -> 250ms for restart --- cli/src/zshell/subcommands/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/zshell/subcommands/shell.py b/cli/src/zshell/subcommands/shell.py index de8ca3b..4b30da7 100644 --- a/cli/src/zshell/subcommands/shell.py +++ b/cli/src/zshell/subcommands/shell.py @@ -42,7 +42,7 @@ def restart(no_daemon: bool = False): result = subprocess.run(args + ["kill"], capture_output=True) if result.returncode == 255: break - time.sleep(0.05) + time.sleep(0.25) start_instance(no_daemon=no_daemon) From 16e84ca9983cd4dfc81a1625451c2bfc0857aa21 Mon Sep 17 00:00:00 2001 From: zach Date: Sun, 24 May 2026 18:21:37 +0200 Subject: [PATCH 10/11] fixed region selection for recording, plus cache file cleanup --- .../__pycache__/scheme.cpython-313.pyc | Bin 24035 -> 0 bytes .../__pycache__/scheme.cpython-314.pyc | Bin 10447 -> 0 bytes .../__pycache__/screenshot.cpython-313.pyc | Bin 965 -> 0 bytes .../__pycache__/screenshot.cpython-314.pyc | Bin 1060 -> 0 bytes .../__pycache__/shell.cpython-313.pyc | Bin 2181 -> 0 bytes .../__pycache__/shell.cpython-314.pyc | Bin 2622 -> 0 bytes .../__pycache__/wallpaper.cpython-313.pyc | Bin 1983 -> 0 bytes .../__pycache__/wallpaper.cpython-314.pyc | Bin 2376 -> 0 bytes cli/src/zshell/subcommands/record.py | 2 +- .../__pycache__/schemepalettes.cpython-313.pyc | Bin 1388 -> 0 bytes 10 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc delete mode 100644 cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc deleted file mode 100644 index 7e9924e359f43ab124a1f7be44fc065360606053..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24035 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 diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc deleted file mode 100644 index 71fe8172881a230ded2b282cf4cf25f1b83c5f2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10447 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 diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc deleted file mode 100644 index 91589d5d4114af75e7adc499f1421a33f2c827aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1060 zcmd5*F>ezw6t>TImyot86_FT1K@me0(c~CHkgBL7lqHQ$5mO7gx^6GzlDj@%hGsya z9kMb|DPz|BAf(7$5U?OI1R}(WeaR`11x76Sz3=%wKREAvs20uNo&9p-;+) zhc*Y(fdoDD0@?T(3TGOJxQJ|hABWl@u9@+ch0dYU+z9nUy|%LO#3=UL+U-TG`IlJo zTWrF{_fg*Xq7qhVoK|T=P9o>@wG=&cAmwb-;yc9)Qs>Zt9-B5Q;_cXw+Qv(^wq%nf zTepqJ^E2)t+m!Vs1Zf0R=+yB%VFnG_WFT}uVD0({3xm3hHmf5dQoM5%fKM6cf$u*eJug-1z^p4yvc19s;P>DN>5@Cz6ORt3y(*R6)IbNGqYP z0ym`)s}VadPohA`$R*|bXOarTv?9qGmv)TOA3d&mtn5|w-`5{Kl1!Y$$g#~iVILDLIrxo|*o<^BNPjCbwD6bH48wC~Nl_vX#} z-n=*4NhU`Sj4R(IH=Za6Jravx#QjOGK&h z?=L9Hk)=dm6U+j=sZR85wPS3PCdoxJiW!+e8)O3qK4|QieOl;@_%XK8knPAZwy}_H zVz@2j>6HL`pU*&6=OMphWUv{}CCw4|61lNlG9qM}IXZxKyol3de~1l6TII@3wx!Hj zT-#zL+i@%*4~B4{!q-^@au2Nra zeas_P$+jx{Dj#8+>vif{He+0+n>9}Iw8-{RM>ygi>Ls^o>sxuNq+cm}S?X@smdEt1 zx%E7qyXoncQ`Q-^^ls=nIJ4YpHD4<*U4l7VzePoDNg~RTodU9rekWr)#%<%9OygW* zcK7|g(=DRYF>z$P=H4je?W$X|{G@^upL%K|-J}iKQSZ_}CPXFo5~S zncc&48bx1rc@A-b@nEZe@(r%_hmEn?%}z^*=Fj}5p>B_ z36N`0e?{BlTGjSSZh=OFS6C==DtwB+r9>1$9xc_z%m9BA=IV@5mg`SK*)# z__RtVK|)^>L;@D!O;2|_Nm@%X15)-5kpGs8pI4iy>@U}IE%Ld{NE%;GpP=Gb$RpmZ zx=rb*oG*(xSM&8ckNQuOe2X|)cU?zzaJLm?fr(4uv5U00S+#2(SD8oQHp{>Ss(}{b zv4yHz*mUegdIq%Od0>A6X{#9H2k3@r{AP43TaS_v6*M|VGhGp{q0_v%7-T(jq diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc deleted file mode 100644 index f3b6e65c82657ff6bd8e73ad4591495d5ba254ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2622 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 diff --git a/cli/src/zshell/subcommands/record.py b/cli/src/zshell/subcommands/record.py index f568137..986687c 100644 --- a/cli/src/zshell/subcommands/record.py +++ b/cli/src/zshell/subcommands/record.py @@ -120,7 +120,7 @@ def start_recording(region: Optional[str], sound: bool): monitors = _monitors_intersecting_region(x, y, w, h) framerate = _highest_refresh(monitors) - cmd.extend(["-w", "-region", geometry, "-f", str(int(framerate))]) + cmd.extend(["-w", "region", "-region", geometry, "-f", str(int(framerate))]) else: monitor_name = _focused_monitor_name() diff --git a/cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc b/cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc deleted file mode 100644 index 61bbb4752ce20bfa3ccccc775f31196b894f6cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1388 zcmY*Z%}*Og6rcTGfASGiwviLX}(xmq4K?Lrz&~HCZ-z>3Y|h9aq2! zi9^$>Qhg|r53Q8m+JB}ZvQ)vSsVeov&B&2@?abO(;z|2^zu$ZFvGeBbb~BkIVD`hW znf+fx0RH9T+7f-z{ezKHa2G%Tg$=MSU}1`LaYI~}uoQD?Lta;~G6gIl51Ewj z1t;K$m6#WB(o!tVQj4O(7PV4v^ke4tZWVHue3ODe6T65Y$461bgtX=m=Cn;zuY1AX z4&&+z93HuW!-rp+)F)kwkyBs+EI@!oC}8O>uw+YtBHt!v(tybWrVNP1<%X+->-rr)~RX1Nr^TkZr&4a727BaD&jc zvCMa8Q4|CrLBtD#h((8Zbj-FR9&&6%2=<;gh|6=sEZ1cZpcS(k)?D)lIaTuuk8I;` z-*rf29?d>Sc=jbR9p5t}?3hPU)%AU|K|DV)Bd6-t+uj+YcqyV!7<>!< z$qb)-c|J6HvUQ#vIoUjq<(ScyjdNr2c=gp{Gxy!YKjle0em$AWRrkQADt1W&2Ts4? zSQY@jF2CRI8iP~tjA757^qcrvbDsy#cwfZ^g{L437DXry+P%N-9Z-YoAEiRT3#;ASC*-I|53TPTBK@a>GMacOfM7{?k|?8y12Yp zDpm>#=6?X3;*jQ$;gDr;lyeZN*Bg%G1rKY;ajG67A=S2@tishDxK&8g)ZpuJBh1T2 zjT&OT=pp|wY&fAG;yL#A{OO%pC5QaW!n|zpJyIzmI6fWCl}kI@+fU2o$6NMhsa#%r zT-x~x&+w6B9Qg5jcNkYkU+FdOXZTZ=;AM+`V$hKULHHX?zXkW+f{7~?h^gkCH^TUT zqAGmY0Svkl5RFbOM+ITN2|Iwf7JSFul@5%LF4FHc58COei>%Qy+S&X?X1t}hGt+~3 y?sn^-ox69HQVsD8ym_nn_1Vbun?(K{5Ct)Q>;C~S6H77x From 9c36f0de5b27882e73d5c0562246d04acbbef785 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Sun, 24 May 2026 18:28:32 +0200 Subject: [PATCH 11/11] pycache in cache removal --- .../__pycache__/scheme.cpython-313.pyc | Bin 7101 -> 0 bytes .../__pycache__/scheme.cpython-314.pyc | Bin 30626 -> 0 bytes .../__pycache__/screenshot.cpython-313.pyc | Bin 978 -> 0 bytes .../__pycache__/screenshot.cpython-314.pyc | Bin 1040 -> 0 bytes .../__pycache__/shell.cpython-313.pyc | Bin 2184 -> 0 bytes .../__pycache__/shell.cpython-314.pyc | Bin 6472 -> 0 bytes .../__pycache__/wallpaper.cpython-313.pyc | Bin 1920 -> 0 bytes .../__pycache__/wallpaper.cpython-314.pyc | Bin 2436 -> 0 bytes .../__pycache__/schemepalettes.cpython-313.pyc | Bin 1388 -> 0 bytes 9 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/shell.cpython-314.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc delete mode 100644 cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc delete mode 100644 cli/src/zshell/utils/__pycache__/schemepalettes.cpython-313.pyc diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc deleted file mode 100644 index 71fa4f894106bca816f890854e4b585d2df759bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7101 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 F{U1Y~pv?dP diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-314.pyc deleted file mode 100644 index 06584ac0875cc72ca33cd0db9527c59ae4813dbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30626 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 diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc deleted file mode 100644 index 043fc1df55b2e6a5d932ad16cb9504f6c6f86496..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 978 zcmc&zF>ljA6u$G>PDqoM(u#pl1YN2~1T&!Z3aU3eAcZ`urO$o(e{Lh4DTKJ;8Di8 zAkgay-GK(5piu28_N=DYVOHOvP3u`JcnRJcMgwm3i$@L=PXmj(EsF!S<|-}OjC!4p z(>>-Er@&a3H@)DIe^?0Q2QFG(1nZ~F4EdS3ldy4=3pdcQl~AMbrydpKRc z`)=o&;Prdc2V3K`@(R<(rI28w46AbCf4EIhj|x%>(h@{Q-Q-iLu+QqC9xY@Q+*F{B z2)87NY^3`2NmK{7<XHFDvoZw7jFlSE9~^G~`roBRKOJfNCg=y7C2ad|#yE zFA&{zwCA6vN>@7GanEJDke7?)e}?!A2{VE*zCx>4DElR~G0;DoOT+eg`=T=-GZSgX eF#k4xv2m?wxEvCst<01+%lww9L>W~xKkQEidBfQN diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc deleted file mode 100644 index f1921ea0037d724a68c84ccba54f287a3d7a389b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1040 zcmd5*KX21O6u-02PDtC75+sJGLRAM8wTYLasuHR|swgm+V4~0=1-Vz3gxInB&Ka5k zg?7jn04ZZfvN7f(FtS9It_uPdwm`lBcTTK8mad%i{`~H}dw1{8t)&-INUYV}8*lDo zguY7Px#A)OKC22Q^xEfD=D(8l@iQ8m&6CZuV53V$Fj9eCja9 zRcJOivEeoAp^B45-m!RmXJ=5rz7mXEzR+ z!6-ORgH`>o5S(z0g*Jq+B*I-2#MT6BqaP&QF;C6+8{NCzJ0G^s%jb^>WDM3=~m>?$|(vrzk;JRRZJ}Szq zqsS3%iY@8DDHvOLq#|W;7^%bLKeoNG?YFS);V6Ya6bipR diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc deleted file mode 100644 index af12c926f11d084ecb69ceb0cd57ba02dc91c7c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2184 zcmb_dL2nyH6rR}~ukAQaS{w=_4GK}!#?W*@avD;FKnp5Jh;5opDx_Mfob}3fy!N^? z8$ojl?IAamNEG>4Zpj6OTf~KHu8}X%R7j}h05?bO59ph**IrDqrIwNQy*KmTym{Z7 z_huXM_yB@&@%JAKVHKgLV&aczOK5zL5qgMBWa2LoZE{Spj!fkyrb-$wY5tZDpF}gQ z2_&?s6XYuNWeBYpO1fit3gY{LQDfj+j8fNiX| zE#&D#YX)--dl3+r$WCx`wP8;qpNmAh<1nYOsL z!Sc4_SYq8D!U5bWYAgVGh;IAqXh~^{ZDA7KCjP|4I-Z7!shH}VGJ$d^NeoVk1;<(5 z!#rf=ZL7Ga@&UHKTA{9GGsacAUgji2b8HVagd_f`o_9;OzLBx=`sW32k-BTP`s^hRMq$Vg*e}M+jvgbvnACm`W=}s!3WY z3K?({W%#noGz{icgq+0m6fh>jnV`c!d5C!#>e1Ig7D2OjfCNFMs^@n;`Z@X2wS#j9 zXO0q|9FiLOO5%I*?OuodF9Yg@5V%^XSe&rD`%M4^jl&r-1POt@E~bJc;A7)Jf&gZ! z7j_mN-Fo!JQR3qMXEid{Bl!QPG*!pV^$7P35w0Mj1OHV-GThyf8oAUX&Reka)spPj zON$dT)T$fJpd;X&6D#95oH(vk?15zzOsOCu>+C%s|CxGi_uHey?7`)OsiVZTL+Fwl z5+K*0{&Kd*wUX`S-7Jqa`5n=`mUuAy(e9fxth@^P71Tt%(t21{6#2Xadq?Jgz6A#b zz$aBY1}pTeAQG?$Z(^d^Nzz)9NmylbK>Fn3cw}_@!xI&coIQR!Dfqj`AIvmV9GaDx zN#g6tQ&jvCdC0q0u_+yt^0JV*nyFNHxb;NIH;I!~*L7qkH(Np$nz$Suxk_{ECA;i# zm3b6ywE#?@>uMz)nJ>B7b;n+y7eFhX3HBF|x{5J=j7~pBgHOWao8%8IwpF}ed{Ej{ z>l#u*TVvmiJs3YxFn+(GB4xNPqOX9}%HFIy4 zg-R(Irx=ZeLb?Ns6@l*q$@j_u3fO z2~Cmu(2+eecjnB@nVIi=b7uDWye#Sb%x)y$J+j*tQwB@*{K(TtSS zIQGqJJWB;lV5z8yVIuj?ahh#JjCstiYH2SSsD5aU5l75lt1)wCy~KCbWZR^6N$4Vy z*hMm%GMwgGqiwrn18KVS7L)KL%>sv$CT_@Y#S{By2 z$6UW!+6y~20DFhw6;ATN+`J8Q^GjTigf@MKBGDwqX0Sm7-$&)yV+3PB+*-roOlkQk?Rp@p z^w6nXE}a|iN#|58kxR-wn$m;v;b_REyVR*md8#C3Rn-NM)WrlHS9KSap_^P%Ny)k` znMo%nb>BBJIrU~z&TDBUrwi&eRky2JN~Tn|U8QMF*6k@7n}8yADyvf&O~t+L(GN!^ zl&l;{&_p)!T3S;h*ZVIeX#W*00)0nRnv7gmC*({f0@@^%Y&MZgsS#EZ&R?Urk1X;+ zM*S{C1@bp<*X_|;qxVl1hl+y_&OJO?_8u<`Ejhdu$F>E>w&~+#NB6R?v*O$JiEr0@ z@Oa60V%~XTS#;by{r2gKxOqX`d?$WyDOy64$Hr&?inhRCeF>rh`GPpPeXAJVPpx1wqp>f# z8LFAmkg{Oe$)7f8Cvmc;+NCk!FgeRhT!Ssaq%B+G;#@OZiUE%|1{2FMcVi8)I5yA6 zc}oK@-~iw~&c_f24Z-Z~5R_MK*0QPCrUqg7>?LvDw4w>ry5m`yDgzwFaX|u?xgq?= z^Ad*F(yoqCBpX1=ex2{n!9R7L;`Ux|Ph_Z^NL@3nI~sCR2UJj`DvImPY!hgJ;`DW! zs?l^_w`G*8V6V956p4x=pHWmMBvRlyLUAGJ4zpB61L*7N=`jH60|uemn8_rx7it+q zi;yXhWy>f}77si)`@2K4(%isY-(ukP`R|XGy<=dY-p<=2KN+cbdl$UDC2z3e4J~*> zCGWn%(4QUNC3m1`|IqV+=a;^+JG|V{Rq5#aq@%C+MyVq_?+HI`-An$id)@DKSNyvd z{JTs3Jr#fdg1^7ykGyNQ48M4wGE`SPlbICsX6m=L?g$)9vpn4j zqQ**n334HhZij@?oMFVwY*~bhqoQ4-?Q-0XRgCVQXGu*LsAmE7V7j2$7s#-wBXEuh zRG@nTP~f64Dt120F-6$meZ~gCHp2$dKB(=1zlz%nWGQysIrK>Eu8nH;{@g1-gU};g zYw9?@HFYPq7l~@`UB*{?Yf69+3l?AHKrNWMS-zojeJ2^VPW6~|ep_7w1DKp43H81~ zo?CCbI5!B!k~+sc1gql>`69q~%{+|Je-2)Nkzlg|oh$#$^1^#CS2fXTrQR)bW=4LR}H`1`-WFng5lhN5W5*+?y-md?t08=P#4rsUE| zMkBy68ClLVXods^P2HISlFFoWGUF8$0S;_pVATOG0z+#*l;S|@6^Ib6zMIh-(YpiF z2d4M_{OE567RABk_RiaH-FmCkzOxuyY~Nk@*0RfYJA5l#a=kQtq3qhd?B9NG$Io{B zN}RD5-~4s^oLKgsde^?>_E+421z;7S><%t@{L4*iti|T}O)j(r(w(&$W4y)SPg~t{<-RMrtp<6(4?i8)}(XU`3 zMqkAW6{30v@>KEQgXqlVnG1`7SLae?@0ow=M-~r!c;tg4mEggJ;K5SxP$hVDA$YX3 zPUo@(&i=SzoUQvl^S^?tX5JL~9}NL;)l9Ml!fUu%1I5ipYr?3l?5Q@IB%tH33mIj+ zirr=1@SAeG!!HBan+wf^bCj}4wSveUI2Q_;{G*mPA$Ow;|+tmkwn+{ z79`QSko=!y0Vjk2$+AlXjlhR4CKH*AE@qVEWEH9uiSZfQJb;B5oq)f31EOaTSEbE| zTOT?X1IOlu<^~r7XXb}5mc5A=fJ3;V*SyE7A4Blg!yIRcDcIVHm-w1@DG9^iQ5m6D zx*u=b)evDe&0K!n4z9|$tm*cwtW78>-EE{}_*@d=;Wb2~u%u~KYjq_!10AdA>fn_? z> zRG8HJ&G`6XnVk?9n!N*5Z`A8MgM_BOM+@eEVZP0CYf^VAu=hD;cJx))#d>>#8}}d- zQRH*_HH^^hGH%>`eO1>58?lzBvF;8;>$Aa+e^@zpaUOo77Z(GGdHP1#d-VlcWJu8Y zD=NHCBz3#-lo#TLLLJ5d$Q-i}P6T~7-KJg3!y5#9qp+RFye=g2dEHTc`7_@8dQl$l zkrb~7h6~4zKqMsHd7O?yU6?oWy5G4cG>(OnS#Vt3!1yfOJswjiw732(c({q61Vbg%MYl1~J}x36IC3m-hV zt!%ZbKj+~tU#*7RinFc;uDaD4$knxJ=yJtpwOQqD)?koZ*;H5alp1wymJT2PL-hC2 Uj|WPJW1k~`urdFE%Cg1y7ZxR~pa1{> diff --git a/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc deleted file mode 100644 index e70c525ab8f2494bed48f13cdeb03decded87504..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmb7E%TF6e7@yhMhu=VWC^SF}qKZs0+e$`xv`L$WR{%NS#l6^Sv@Bb*V6T_ib*msn za*_j(9H0_uiF)A(r?yh1{tdmgMOCeds-iv)+(6DB(3!Q@ZVzqJIn4L_zWHABecwzq z91Z}wzPtXJ@i_wEcgA?jUkBA;2*6XI00qtfT%!;}%5yW^G{Pv#WN3z;7O*faV$tRK z8EM*weNi9-MVN=!pM|Lo&vlayfYCaGgV|uJyLsXv?_3eHz67U8uYncbli~1x+w=h? zr1-KZ>!ZxL0i_fRho9dE-hNPsOh#%5H6X7S8>jc(S}oXn`Is)lk#%0pv&v3wk%H? z&KxeT=$d28>+wYu$JZQL%Nw$dHMw?mnYz@9g@S4>*>a-_Bi20}rtaL00sCFLmBAl; zWFz@7xtrJ<-MjSZjr|Yyr+#Q3u5?`7xqgOVM}K87wttzSH!35S4>Am0t-Lo@MNpW4 zRq6tepkZ1i=dMv}PqE}M&Z2E0!Nq(D-&G66lIduy?A~g$Vb^^eFKa^@jMkfIqBKf1 zn&PeboDM<5%Hqyr$$d3E!sTferZj)&4vk-WRO!|O|8 zb~OXE0C2*JZ&>vDCroz2>QB&Iax&(}F6N7tPDj@^)^#Fc-KA1;{AOxgSs>y^?pwvI z6(lsNmTcQl&G+eKPz&{AJtkoGv*Av*b-AvMLJs#*WHXy6TbOnbkU+kut=byabrTO# zK|9kqq+1!hI1hrY+e43sb}~nS{_?F#FtUAR>q>d7;tOrgZ%I3YPa=DRduz`w?T>vi zQi-%}uWYT<1@q5_5BP)mL+Pux4nyB}kA747_WsxRk0Rq+==jwXH_>q*ygjrvw43?4 zGyY>|{9yH{^V(71?eeW-UfP&?FtwT4d;KRqido7rc*1TRYs0j-fC$b#`b`m$62r`4 z_D*PZZ_m25t(8q;&na&#Vv!zV);}UFxK>EDEF#t4yZg9_c*k;#qDem=({amm2;8u> z8v5QT6qibQ{RV!Mx?!EQzogqKf)G9jZO=jIPtfx#82AO8|4r&G^T%RvWA)+cqe2;- zihvU~ER=_XYC!ZztY)P3AI*2ZQHYtXP+c# ltZ>g6LS2DVL{F(n*TsK153=)fpsV`@^W(-j<0x`3^cPiyeX#%l diff --git a/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc b/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc deleted file mode 100644 index 37f69d41183976d4731e942ad4c79a58f6a2222c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2436 zcmbsqOKcNIbY^GmU3(o9oTLc^N&+<0X@XS|)Tl)WN+FKa8skP*RYKB@vrU%xv&^oG zh(u*RRS1=u96<7+NI8ZB5|t{ohaRe)I7SUA=|I(}p98nh(DvFlW3OFXDn#m&_RV|q zX5QQPomYYlegv>*AawQ)LFiY`xFDB_jU^xoXaptjAaY78b};bLpcEwz*~RzBpd9r$ zo~YOH3SJ&mqN=0rLi81yz~ za$I*NQy4DrkAnms1PpEL1yn#uG$Qq1MQ9xMcA!&u5-0F5NJJ&AK4>Yx)1%kEYJ?Z-VX18V};@lqX6YWZaSeL3NIt!#4_q#xp_Fk)IM zCZ`~dlvgh!w&4sxAU&x`BQ+HZ6Xu8DSTvV1Y?~39&oWu36LuJj^CHk)Gyqp=$VEI% z_5nZz^qU-+>s3C+>yswXZY{Ee(J0 z095n%)>MZA8zO$+2#wFKj^Rp7t8t9;+NgtSs~nJewpWD-shXevt&0q+uI31VXv@?G zJk!jqm3KzXQgh_;4(BXr3Z{*v^K?|tTt^PaREGna*=fgDo} zM5RhEC4k3W)MyhI3<2Ub+J-xyaP(;F_D5>qk=ig9xE}a4xK6OI?N35N-gN@fr+yS_ z{|~vwVFSrKntG% zaEgba4w5hz`l|IT?LkR-1l44d^g~fjY!N!-5nLmaxorGMSwGKA9n@#GcMgMho3SoG(|V0`^VY#OubMg-=1nLd-sn=*wG$;JH-qjf zGP$W7L0$7GG7^ss#7qRaF)e75u#fUWU~gwv~5WT|u>0D~cPEo_i z(w9NRhnM{wpaOc@hP1}H?(5z2r;4qhW`{)V~k+3p*sAGGv--_pA{wcPUhvj2_3u{Bwl ziC&6cJ6(L~2f0HuC=71toINe|rkJ<%$c6FaX7De(h4O{A17cp7D`s{=Od80@;M*bz zrN}CLB&E$UF@Y$5@t9{wj3J_17E{U(W@+s65Z*?@aw)#*p-gT(pEeFt{t)nfx8DZ@ zQwQURXzN21_#N%|8SVZFwf&;(EXZqKZD#87)Rjzutb38Lrz&~HCZ-z)Ag=1JFb8e z5{IU})Q3{}&`LSB|4c<>se(~cRqBbJj2tP~&a90kp0vOB`@J_GJ8#}@H!U+W-P6Y=CtE3sann8{)czrIAm~VMzrUCMUoP8S9oh11z1*NG%J!VX;bIQ<-Zjdrb{pDL8yj z!3j8GB^Csnv=mFT)Pkt6MXeMZ{gnB=8~NM?-y|>4#4aMp@lg~pA+0%tIc*cw>t3+8 z!?^k!hlg(9@Znb`^-0%a0)Jrs~Fs<;@3_;--ksczc=s=2mJleS$8cN;$EY1@9;Kz=_nWZTa@91-6O+#s}V zEc4x26a_&@5b?qwV$mTU9kcC-ha4Lbg1u)A;_}=u%XQfUXvM6CHP<{uPSyO%BilH9 z;W{KT59gjCJol2Aj_;WfcFe=5>iWLfAf6wYkyCYRZoPNmD!*E4=DxrGr#y+ruO?Hu>h9ZA#V%>!!09&} z%L2gH<@eiNV{ihVGVIyoeiL75?q|SL-dC|f;R(osB@v2)cJHry3*@CODlhC;Di^#W zd8t=QowZiY_5wmB26+L0$dVDCG=&X@G|AtRgm%>-c!~x1Qj8J2h8Rz6KrgRjSpFfSW5 zYKZlshx~)E;e>vO=h@ryr*~$R9Plp-^RmVFNTrD2_;fT^D(-A=KPiQ|v9T=aSr$1=!x6@PSS)*mNvoq(J@s{4sOb_C@ xo2~tJ?#^XOHN;bp>x=^BqtnTSjwH^CN7}3L=8fhzrz6vE5;O0BD2VY}{}06FORWF^