22 Commits

Author SHA1 Message Date
2eb48556ed implement get/set recording directory
closes #3

minor bump
2025-06-29 16:35:00 +01:00
cb892d66d8 run ruff format as well 2025-06-27 12:38:35 +01:00
fccef1e2bf rename build workflow to release
add ruff workflow
2025-06-27 12:31:35 +01:00
3c77be2ff9 reword 2025-06-27 08:28:06 +01:00
e8d0fcf56d upd button name in README 2025-06-27 08:25:00 +01:00
69a0f607e4 upd screenshot 2025-06-27 08:23:27 +01:00
40429892e8 minor bump 2025-06-27 08:19:42 +01:00
1a5c0d4537 use help output in README 2025-06-27 08:19:18 +01:00
ebad2f51c9 upd screenshot 2025-06-27 08:19:08 +01:00
528573cd5a process pause + record mouse/keyboard events 2025-06-27 08:19:02 +01:00
3eb37295c2 register pause + resume as subcommands on the CLI 2025-06-27 08:17:16 +01:00
ef68915f6a implement pause + resume 2025-06-27 08:17:04 +01:00
b161c1ec3d upd description 2025-06-27 07:54:12 +01:00
e37ae8dddc upd screenshot 2025-06-27 07:50:46 +01:00
1d6fbd0bda add tabgroup to mainframe
add pause, split and add chapter buttons to Recorder tab
- they are not implemented yet

add timeouts on requests + handle them

add obs connected status message on GUI load
2025-06-27 07:47:56 +01:00
0814678278 debug should be a hidden option
patch bump
2025-06-26 14:38:53 +01:00
68041f1406 fix bug with parser (regression)
patch bump
2025-06-26 09:56:53 +01:00
bba2361964 add available themes to --theme help string
patch bump
2025-06-26 08:56:32 +01:00
d8cdae61a9 upd --help output in README 2025-06-26 06:54:47 +01:00
a43813fc00 fix help string for theme option 2025-06-26 06:53:36 +01:00
87dbd0b8e5 typo 2025-06-26 06:52:20 +01:00
00dbe43479 patch bump 2025-06-26 06:47:50 +01:00
15 changed files with 428 additions and 185 deletions

View File

@@ -1,62 +0,0 @@
name: Build PYZ
on:
push:
tags:
- 'v*.*.*'
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up PDM
uses: pdm-project/setup-pdm@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pdm sync -d -G build
- name: Build addon
run: pdm run compile
- name: Upload build artifacts
if: success()
uses: actions/upload-artifact@v4
with:
name: pyz_build
path: ./bin/simple-recorder.pyz
upload_release:
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') }}
needs: build
steps:
- name: Download releases files
uses: actions/download-artifact@v4.1.7
with:
name: pyz_build
- name: Display structure of downloaded files
run: tree
- name: Release
uses: softprops/action-gh-release@v1
with:
files: simple-recorder.pyz
fail_on_unmatched_files: true
prerelease: ${{ contains(github.ref, '-') }}

26
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Publish to PyPI
on:
release:
types: [published]
push:
tags:
- 'v*.*.*'
jobs:
pypi-publish:
name: upload release to PyPI
runs-on: ubuntu-latest
environment: pypi
permissions:
# This permission is needed for private repositories.
contents: read
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pdm-project/setup-pdm@v4
- name: Publish package distributions to PyPI
run: pdm publish

View File

@@ -1,26 +1,62 @@
name: Release name: Release PYZ
on: on:
release:
types: [published]
push: push:
tags: tags:
- 'v*.*.*' - 'v*.*.*'
jobs: pull_request:
pypi-publish: branches: [main]
name: upload release to PyPI
runs-on: ubuntu-latest workflow_dispatch:
environment: pypi
permissions: permissions:
# This permission is needed for private repositories. contents: write
contents: read
# IMPORTANT: this permission is mandatory for trusted publishing jobs:
id-token: write build:
runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - name: Checkout code
uses: actions/checkout@v4
- uses: pdm-project/setup-pdm@v4 - name: Set up PDM
uses: pdm-project/setup-pdm@v4
with:
python-version: '3.11'
- name: Publish package distributions to PyPI - name: Install dependencies
run: pdm publish run: |
pdm sync -d -G build
- name: Build addon
run: pdm run compile
- name: Upload build artifacts
if: success()
uses: actions/upload-artifact@v4
with:
name: pyz_build
path: ./bin/simple-recorder.pyz
upload_release:
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') }}
needs: build
steps:
- name: Download releases files
uses: actions/download-artifact@v4.1.7
with:
name: pyz_build
- name: Display structure of downloaded files
run: tree
- name: Release
uses: softprops/action-gh-release@v1
with:
files: simple-recorder.pyz
fail_on_unmatched_files: true
prerelease: ${{ contains(github.ref, '-') }}

19
.github/workflows/ruff.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Ruff
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
with:
args: 'format --check --diff'

View File

@@ -3,9 +3,7 @@
[![pdm-managed](https://img.shields.io/endpoint?url=https%3A%2F%2Fcdn.jsdelivr.net%2Fgh%2Fpdm-project%2F.github%2Fbadge.json)](https://pdm-project.org) [![pdm-managed](https://img.shields.io/endpoint?url=https%3A%2F%2Fcdn.jsdelivr.net%2Fgh%2Fpdm-project%2F.github%2Fbadge.json)](https://pdm-project.org)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
A single purpose application for naming file recording in OBS. A simple OBS recorder app. Run it as a CLI or a GUI.
Run it as a CLI or a GUI.
--- ---
@@ -30,7 +28,7 @@ pipx install simple-recorder
*with pyz* *with pyz*
An executable pyz has been included in [Release](https://github.com/onyx-and-iris/simple-recorder/releases) which you can run in Windows. Follow the steps in this [Setting up Windows for Zipapps](https://jhermann.github.io/blog/python/deployment/2020/02/29/python_zippapps_on_windows.html#Setting-Up-Windows-10-for-Zipapps) guide. An executable pyz has been included in [Releases](https://github.com/onyx-and-iris/simple-recorder/releases) which you can run in Windows. Follow the steps in this [Setting up Windows for Zipapps](https://jhermann.github.io/blog/python/deployment/2020/02/29/python_zippapps_on_windows.html#Setting-Up-Windows-10-for-Zipapps) guide.
## Configuration ## Configuration
@@ -61,37 +59,38 @@ simple-recorder
![simple-recorder](./img/simple-recorder.png) ![simple-recorder](./img/simple-recorder.png)
Just enter the filename and click *Start Recording*. Just enter the filename and click *Start*.
#### Themes #### Themes
Passing flags is fine, however, for example to set the theme: You can change the colour theme with the --theme option:
```console ```console
simple-recorder --theme="Light Purple" simple-recorder --theme="Light Purple"
``` ```
Available themes: Light Purple, Neutral Blue, Reds, Sandy Beach, Kayak, Light Blue 2, Dark Teal1
### CLI ### CLI
```shell ```shell
Usage: simple-recorder [OPTIONS] COMMAND Usage: simple-recorder [OPTIONS] COMMAND
┏━ Subcommands ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━ Subcommands ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ start Start recording ┃ ┃ start Start recording ┃
┃ stop Stop recording ┃ ┃ stop Stop recording ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ pause Pause recording ┃
┃ resume Resume recording ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ --host <HOST> OBS WebSocket host ┃ ┃ --host <HOST> OBS WebSocket host ┃
┃ --port <PORT> OBS WebSocket port ┃ ┃ --port <PORT> OBS WebSocket port ┃
┃ --password <PASSWORD> OBS WebSocket password ┃ ┃ --password <PASSWORD> OBS WebSocket password ┃
┃ --theme <THEME> OBS WebSocket theme ┃ --theme <THEME> GUI theme (Light Purple, Neutral Blue, Reds, Sandy Beach,
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ Kayak, Light Blue 2)
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
``` ```
For example: To launch the CLI pass any subcommand (start/stop etc...), for example:
```console ```console
simple-recorder start "File Name" simple-recorder start "File Name"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "simple-recorder" name = "simple-recorder"
version = "0.1.3" version = "0.3.0"
description = "A simple OBS recorder" description = "A simple OBS recorder"
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }] authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
dependencies = [ dependencies = [

View File

@@ -3,9 +3,11 @@ import logging
from clypi import ClypiConfig, ClypiException, Command, arg, configure from clypi import ClypiConfig, ClypiException, Command, arg, configure
from typing_extensions import override from typing_extensions import override
from .directory import Directory
from .errors import SimpleRecorderError from .errors import SimpleRecorderError
from .gui import SimpleRecorderWindow from .gui import SimpleRecorderWindow
from .split import Split from .pause import Pause
from .resume import Resume
from .start import Start from .start import Start
from .stop import Stop from .stop import Stop
@@ -16,9 +18,6 @@ config = ClypiConfig(
) )
configure(config) configure(config)
def theme_parser(value: str) -> str:
"""Parse the theme argument."""
themes = [ themes = [
"Light Purple", "Light Purple",
"Neutral Blue", "Neutral Blue",
@@ -26,8 +25,11 @@ def theme_parser(value: str) -> str:
"Sandy Beach", "Sandy Beach",
"Kayak", "Kayak",
"Light Blue 2", "Light Blue 2",
"Dark Teal1",
] ]
def theme_parser(value: str) -> str:
"""Parse the theme argument."""
if value not in themes: if value not in themes:
raise ClypiException( raise ClypiException(
f"Invalid theme: {value}. Available themes: {', '.join(themes)}" f"Invalid theme: {value}. Available themes: {', '.join(themes)}"
@@ -36,19 +38,31 @@ def theme_parser(value: str) -> str:
class SimpleRecorder(Command): class SimpleRecorder(Command):
subcommand: Start | Stop | Split | None = None subcommand: Start | Stop | Pause | Resume | Directory | None = None
host: str = arg(default="localhost", env="OBS_HOST", help="OBS WebSocket host") host: str = arg(default="localhost", env="OBS_HOST", help="OBS WebSocket host")
port: int = arg(default=4455, env="OBS_PORT", help="OBS WebSocket port") port: int = arg(default=4455, env="OBS_PORT", help="OBS WebSocket port")
password: str | None = arg( password: str | None = arg(
default=None, env="OBS_PASSWORD", help="OBS WebSocket password" default=None, env="OBS_PASSWORD", help="OBS WebSocket password"
) )
theme: str = arg( theme: str = arg(
default="Reds", parser=theme_parser, env="OBS_THEME", help="OBS WebSocket theme" default="Reds",
parser=theme_parser,
env="OBS_THEME",
help=f"GUI theme ({', '.join(themes)})",
)
debug: bool = arg(
default=False,
env="DEBUG",
help="Enable debug logging",
hidden=True,
) )
@override @override
async def run(self): async def run(self):
"""Run the Simple Recorder GUI.""" """Run the Simple Recorder GUI."""
if self.debug:
logging.basicConfig(level=logging.DEBUG)
window = SimpleRecorderWindow(self.host, self.port, self.password, self.theme) window = SimpleRecorderWindow(self.host, self.port, self.password, self.theme)
await window.run() await window.run()

View File

@@ -0,0 +1,36 @@
import obsws_python as obsws
from clypi import Command, Positional, arg
from typing_extensions import override
from .errors import SimpleRecorderError
from .styler import highlight
class Directory(Command):
"""Get or set the recording directory."""
directory: Positional[str] = arg(
default=None,
help="Directory to set for recordings. If not provided, the current directory will be displayed.",
)
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
@override
async def run(self):
try:
with obsws.ReqClient(
host=self.host, port=self.port, password=self.password
) as client:
if self.directory:
client.set_record_directory(self.directory)
print(f"Recording directory set to: {highlight(self.directory)}")
else:
resp = client.get_record_directory()
print(
f"Current recording directory: {highlight(resp.record_directory)}"
)
return resp.record_directory
except Exception as e:
raise SimpleRecorderError(f"Failed to get recording directory: {e}")

View File

@@ -1,9 +1,12 @@
import logging import logging
import FreeSimpleGUI as fsg import FreeSimpleGUI as fsg
from clypi import ClypiException import obsws_python as obsws
from .split import Split from .directory import Directory
from .errors import SimpleRecorderError
from .pause import Pause
from .resume import Resume
from .start import Start from .start import Start
from .stop import Stop from .stop import Stop
@@ -18,30 +21,96 @@ class SimpleRecorderWindow(fsg.Window):
self.password = password self.password = password
fsg.theme(theme) fsg.theme(theme)
layout = [ try:
[fsg.Text("Enter recording filename:")], with obsws.ReqClient(
[fsg.InputText("", key="-FILENAME-")], host=self.host, port=self.port, password=self.password, timeout=3
) as client:
resp = client.get_version()
status_message = f"Connected to OBS {resp.obs_version}"
resp = client.get_record_directory()
current_directory = resp.record_directory
except (ConnectionRefusedError, TimeoutError):
status_message = "Failed to connect to OBS. Is it running?"
recorder_layout = [
[fsg.Text("Enter recording filename:", key="-PROMPT-")],
[fsg.InputText("default_name", key="-FILENAME-", focus=True)],
[ [
fsg.Button("Start Recording"), fsg.Button("Start", key="Start Recording", size=(20, 1)),
fsg.Button("Stop Recording"), fsg.Button("Stop", key="Stop Recording", size=(20, 1)),
fsg.Button("Split Recording"), ],
[
fsg.Button("Pause", key="Pause Recording", size=(20, 1)),
fsg.Button("Resume", key="Resume Recording", size=(20, 1)),
],
[
fsg.Button("Split", key="Split Recording", size=(20, 1)),
fsg.Button("Add Chapter", key="Add Chapter", size=(20, 1)),
], ],
[fsg.Text("Status: Not started", key="-OUTPUT-")],
] ]
super().__init__("Simple Recorder", layout, finalize=True)
frame = fsg.Frame(
"",
recorder_layout,
relief=fsg.RELIEF_SUNKEN,
)
recorder_tab = fsg.Tab(
"Recorder",
[
[frame],
[
fsg.Text(
f"Status: {status_message}",
key="-OUTPUT-RECORDER-",
text_color="white"
if status_message.startswith("Connected")
else "red",
)
],
],
)
settings_layout = [
[fsg.Text("Enter the filepath for the recording:")],
[fsg.InputText(current_directory, key="-FILEPATH-", size=(45, 1))],
[
fsg.Button("Get Current", key="-GET-CURRENT-", size=(10, 1)),
fsg.Button("Update", key="-UPDATE-", size=(10, 1)),
],
[fsg.Text("", key="-OUTPUT-SETTINGS-", text_color="white")],
]
settings_tab = fsg.Tab("Settings", settings_layout)
mainframe = [
[fsg.TabGroup([[recorder_tab, settings_tab]])],
]
super().__init__("Simple Recorder", mainframe, finalize=True)
self["-FILENAME-"].bind("<Return>", " || RETURN") self["-FILENAME-"].bind("<Return>", " || RETURN")
self["Start Recording"].bind("<Return>", " || RETURN") self["Start Recording"].bind("<Return>", " || RETURN")
self["Stop Recording"].bind("<Return>", " || RETURN") self["Stop Recording"].bind("<Return>", " || RETURN")
self["Split Recording"].bind("<Return>", " || RETURN") self["Pause Recording"].bind("<Return>", " || RETURN")
self["Resume Recording"].bind("<Return>", " || RETURN")
self["-FILENAME-"].bind("<KeyPress>", " || KEYPRESS")
self["-FILENAME-"].update(select=True)
self["Add Chapter"].bind("<FocusIn>", " || FOCUS")
self["Add Chapter"].bind("<Enter>", " || FOCUS")
self["Add Chapter"].bind("<FocusOut>", " || LEAVE")
self["Add Chapter"].bind("<Leave>", " || LEAVE")
self["Add Chapter"].bind("<Button-3>", " || RIGHT_CLICK")
async def run(self): async def run(self):
while True: while True:
event, values = self.read() event, values = self.read()
self.logger.debug(f"Event: {event}, Values: {values}")
if event == fsg.WIN_CLOSED: if event == fsg.WIN_CLOSED:
break break
match event.split(" || "): match e := event.split(" || "):
case ["Start Recording", "RETURN" | None] | ["-FILENAME-", "RETURN"]: case ["Start Recording"] | ["Start Recording" | "-FILENAME-", "RETURN"]:
try: try:
await Start( await Start(
filename=values["-FILENAME-"], filename=values["-FILENAME-"],
@@ -49,41 +118,108 @@ class SimpleRecorderWindow(fsg.Window):
port=self.port, port=self.port,
password=self.password, password=self.password,
).run() ).run()
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
"Recording started successfully", text_color="green" "Recording started successfully", text_color="green"
) )
except ClypiException as e: except SimpleRecorderError as e:
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
f"Error: {e.raw_message}", text_color="red" f"Error: {e.raw_message}", text_color="red"
) )
case ["Stop Recording", "RETURN" | None]: case ["Stop Recording"] | ["Stop Recording", "RETURN"]:
try: try:
await Stop( await Stop(
host=self.host, port=self.port, password=self.password host=self.host, port=self.port, password=self.password
).run() ).run()
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
"Recording stopped successfully", text_color="green" "Recording stopped successfully", text_color="green"
) )
except ClypiException as e: except SimpleRecorderError as e:
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
f"Error: {e.raw_message}", text_color="red" f"Error: {e.raw_message}", text_color="red"
) )
case ["Split Recording", "RETURN" | None]: case ["Pause Recording"] | ["Pause Recording", "RETURN"]:
try: try:
await Split( await Pause(
host=self.host, port=self.port, password=self.password host=self.host, port=self.port, password=self.password
).run() ).run()
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
"Recording split successfully", text_color="green" "Recording paused successfully", text_color="green"
) )
except ClypiException as e: except SimpleRecorderError as e:
self["-OUTPUT-"].update( self["-OUTPUT-RECORDER-"].update(
f"Error: {e.raw_message}", text_color="red"
)
case ["Resume Recording"] | ["Resume Recording", "RETURN"]:
try:
await Resume(
host=self.host, port=self.port, password=self.password
).run()
self["-OUTPUT-RECORDER-"].update(
"Recording resumed successfully", text_color="green"
)
except SimpleRecorderError as e:
self["-OUTPUT-RECORDER-"].update(
f"Error: {e.raw_message}", text_color="red"
)
case ["Add Chapter", "FOCUS" | "LEAVE" as focus_event]:
if focus_event == "FOCUS":
self["-OUTPUT-RECORDER-"].update(
"Right-click to set a chapter name", text_color="white"
)
else:
self["-OUTPUT-RECORDER-"].update("", text_color="white")
case ["Add Chapter", "RIGHT_CLICK"]:
_ = fsg.popup_get_text(
"Enter chapter name:",
"Add Chapter",
default_text="unnamed",
)
case ["Split Recording" | "Add Chapter"]:
self["-OUTPUT-RECORDER-"].update(
"This feature is not implemented yet", text_color="orange"
)
case ["-GET-CURRENT-"]:
try:
current_directory = await Directory(
host=self.host, port=self.port, password=self.password
).run()
self["-FILEPATH-"].update(current_directory)
except SimpleRecorderError as e:
self["-OUTPUT-SETTINGS-"].update(
f"Error: {e.raw_message}", text_color="red"
)
case ["-UPDATE-"]:
filepath = values["-FILEPATH-"]
if not filepath:
self["-OUTPUT-SETTINGS-"].update(
"Filepath cannot be empty", text_color="red"
)
else:
try:
await Directory(
directory=filepath,
host=self.host,
port=self.port,
password=self.password,
).run()
self["-OUTPUT-SETTINGS-"].update(
"Recording directory updated successfully.",
text_color="green",
)
except SimpleRecorderError as e:
self["-OUTPUT-SETTINGS-"].update(
f"Error: {e.raw_message}", text_color="red" f"Error: {e.raw_message}", text_color="red"
) )
case _: case _:
self.logger.warning(f"Unhandled event: {event}") self.logger.debug(f"Unhandled event: {e}")
self.close() self.close()

View File

@@ -0,0 +1,30 @@
import obsws_python as obsws
from clypi import Command, arg
from typing_extensions import override
from .errors import SimpleRecorderError
class Pause(Command):
"""Pause recording."""
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
@override
async def run(self):
try:
with obsws.ReqClient(
host=self.host, port=self.port, password=self.password, timeout=3
) as client:
resp = client.get_record_status()
if not resp.output_active:
raise SimpleRecorderError("No active recording to pause.")
if resp.output_paused:
raise SimpleRecorderError("Recording is already paused.")
client.pause_record()
print("Recording paused successfully.")
except TimeoutError:
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")

View File

@@ -0,0 +1,30 @@
import obsws_python as obsws
from clypi import Command, arg
from typing_extensions import override
from .errors import SimpleRecorderError
class Resume(Command):
"""Resume recording."""
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
@override
async def run(self):
try:
with obsws.ReqClient(
host=self.host, port=self.port, password=self.password, timeout=3
) as client:
resp = client.get_record_status()
if not resp.output_active:
raise SimpleRecorderError("No active recording to resume.")
if not resp.output_paused:
raise SimpleRecorderError("Recording is not paused.")
client.resume_record()
print("Recording resumed successfully.")
except TimeoutError:
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")

View File

@@ -1,27 +0,0 @@
import obsws_python as obsws
from clypi import Command, arg
from .errors import SimpleRecorderError
class Split(Command):
"""Split recording."""
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
async def run(self):
with obsws.ReqClient(
host=self.host, port=self.port, password=self.password
) as client:
resp = client.get_record_status()
if not resp.output_active:
raise SimpleRecorderError("Recording is not active.")
if resp.output_paused:
raise SimpleRecorderError(
"Recording is paused. Please resume before splitting."
)
client.split_record_file()
print("Recording split successfully.")

View File

@@ -29,8 +29,9 @@ class Start(Command):
if not self.filename: if not self.filename:
raise SimpleRecorderError("Recording name cannot be empty.") raise SimpleRecorderError("Recording name cannot be empty.")
try:
with obsws.ReqClient( with obsws.ReqClient(
host=self.host, port=self.port, password=self.password host=self.host, port=self.port, password=self.password, timeout=3
) as client: ) as client:
resp = client.get_record_status() resp = client.get_record_status()
if resp.output_active: if resp.output_active:
@@ -44,3 +45,5 @@ class Start(Command):
) )
client.start_record() client.start_record()
print(f"Recording started with filename: {highlight(filename)}") print(f"Recording started with filename: {highlight(filename)}")
except TimeoutError:
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")

View File

@@ -15,8 +15,9 @@ class Stop(Command):
@override @override
async def run(self): async def run(self):
try:
with obsws.ReqClient( with obsws.ReqClient(
host=self.host, port=self.port, password=self.password host=self.host, port=self.port, password=self.password, timeout=3
) as client: ) as client:
resp = client.get_record_status() resp = client.get_record_status()
if not resp.output_active: if not resp.output_active:
@@ -24,3 +25,5 @@ class Stop(Command):
client.stop_record() client.stop_record()
print(highlight("Recording stopped successfully.")) print(highlight("Recording stopped successfully."))
except TimeoutError:
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")