Compare commits

..

No commits in common. "3c77be2ff9cc84f422ea5c3693b4745d9f3e8954" and "0814678278f2770d6548100c197baf4aa3913901" have entirely different histories.

9 changed files with 38 additions and 218 deletions

View File

@ -3,7 +3,9 @@
[![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 simple OBS recorder app. Run it as a CLI or a GUI. A single purpose application for naming file recording in OBS.
Run it as a CLI or a GUI.
--- ---
@ -59,11 +61,11 @@ simple-recorder
![simple-recorder](./img/simple-recorder.png) ![simple-recorder](./img/simple-recorder.png)
Just enter the filename and click *Start*. Just enter the filename and click *Start Recording*.
#### Themes #### Themes
You can change the colour theme with the --theme option: However, passing flags is fine, for example to set the theme:
```console ```console
simple-recorder --theme="Light Purple" simple-recorder --theme="Light Purple"
@ -75,10 +77,8 @@ simple-recorder --theme="Light Purple"
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 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -1,6 +1,6 @@
[project] [project]
name = "simple-recorder" name = "simple-recorder"
version = "0.2.0" version = "0.1.7"
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

@ -5,8 +5,6 @@ from typing_extensions import override
from .errors import SimpleRecorderError from .errors import SimpleRecorderError
from .gui import SimpleRecorderWindow from .gui import SimpleRecorderWindow
from .pause import Pause
from .resume import Resume
from .start import Start from .start import Start
from .stop import Stop from .stop import Stop
@ -37,7 +35,7 @@ def theme_parser(value: str) -> str:
class SimpleRecorder(Command): class SimpleRecorder(Command):
subcommand: Start | Stop | Pause | Resume | None = None subcommand: Start | Stop | 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(

View File

@ -1,11 +1,8 @@
import logging import logging
import FreeSimpleGUI as fsg import FreeSimpleGUI as fsg
import obsws_python as obsws
from .errors import SimpleRecorderError 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
@ -20,79 +17,16 @@ class SimpleRecorderWindow(fsg.Window):
self.password = password self.password = password
fsg.theme(theme) fsg.theme(theme)
try: layout = [
with obsws.ReqClient( [fsg.Text("Enter recording filename:")],
host=self.host, port=self.port, password=self.password, timeout=3 [fsg.InputText("", key="-FILENAME-")],
) as client: [fsg.Button("Start Recording"), fsg.Button("Stop Recording")],
resp = client.get_version() [fsg.Text("Status: Not started", key="-OUTPUT-")],
status_message = f"Connected to OBS {resp.obs_version}"
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", key="Start Recording", size=(20, 1)),
fsg.Button("Stop", key="Stop Recording", size=(20, 1)),
],
[
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)),
],
] ]
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-",
text_color="white"
if status_message.startswith("Connected")
else "red",
)
],
],
)
settings_layout = [
[fsg.Text("Enter the filepath for the recording:")],
[fsg.InputText("", key="-FILEPATH-", size=(45, 1))],
]
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["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:
@ -131,53 +65,7 @@ class SimpleRecorderWindow(fsg.Window):
f"Error: {e.raw_message}", text_color="red" f"Error: {e.raw_message}", text_color="red"
) )
case ["Pause Recording"] | ["Pause Recording", "RETURN"]:
try:
await Pause(
host=self.host, port=self.port, password=self.password
).run()
self["-OUTPUT-"].update(
"Recording paused successfully", text_color="green"
)
except SimpleRecorderError as e:
self["-OUTPUT-"].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-"].update(
"Recording resumed successfully", text_color="green"
)
except SimpleRecorderError as e:
self["-OUTPUT-"].update(
f"Error: {e.raw_message}", text_color="red"
)
case ["Add Chapter", "FOCUS" | "LEAVE" as focus_event]:
if focus_event == "FOCUS":
self["-OUTPUT-"].update(
"Right-click to set a chapter name", text_color="white"
)
else:
self["-OUTPUT-"].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-"].update(
"This feature is not implemented yet", text_color="orange"
)
case _: case _:
self.logger.debug(f"Unhandled event: {e}") self.logger.warning(f"Unhandled event: {e}")
self.close() self.close()

View File

@ -1,30 +0,0 @@
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

@ -1,30 +0,0 @@
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

@ -29,21 +29,18 @@ 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: raise SimpleRecorderError("Recording is already active.")
raise SimpleRecorderError("Recording is already active.")
filename = f"{self.filename} {self.get_timestamp()}" filename = f"{self.filename} {self.get_timestamp()}"
client.set_profile_parameter( client.set_profile_parameter(
"Output", "Output",
"FilenameFormatting", "FilenameFormatting",
filename, filename,
) )
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,15 +15,12 @@ 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: raise SimpleRecorderError("Recording is not active.")
raise SimpleRecorderError("Recording is not active.")
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?")