From 41a129bb9026ea7dd3d23b2e78438b202626ac1a Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 22 May 2026 11:04:54 +0200 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 16e84ca9983cd4dfc81a1625451c2bfc0857aa21 Mon Sep 17 00:00:00 2001 From: zach Date: Sun, 24 May 2026 18:21:37 +0200 Subject: [PATCH 5/5] 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