Compare commits

..

No commits in common. "5aae021aeda0bbecffaf0b72b9cc73f05aff5f08" and "b7c25525a1fba790032c729ef945067a28105b5a" have entirely different histories.

8 changed files with 36 additions and 161 deletions

View File

@ -75,23 +75,21 @@ simple-recorder stop
```shell
Usage: simple-recorder [OPTIONS] COMMAND
┏━ Subcommands ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ start Start recording ┃
┃ stop Stop recording ┃
┃ pause Pause recording ┃
┃ resume Resume recording ┃
┃ split Split the current recording into a new file ┃
┃ chapter Create a chapter in the current recording ┃
┃ directory Get or set the recording directory ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Subcommands ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ start Start recording ┃
┃ stop Stop recording ┃
┃ pause Pause recording ┃
┃ resume Resume recording ┃
┃ directory Get or set the recording directory ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ --host <HOST> OBS WebSocket host
┃ --port <PORT> OBS WebSocket port
┃ --password <PASSWORD> OBS WebSocket password
┃ --theme <THEME> GUI theme (Light Purple, Neutral Blue, Reds, Sandy Beach,
┃ Kayak, Light Blue 2)
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┏━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ --host <HOST> OBS WebSocket host ┃
┃ --port <PORT> OBS WebSocket port ┃
┃ --password <PASSWORD> OBS WebSocket password ┃
┃ --theme <THEME> GUI theme (Light Purple, Neutral Blue, Reds, Sandy Beach, ┃
┃ Kayak, Light Blue 2) ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
```
### GUI

8
pdm.lock generated
View File

@ -5,7 +5,7 @@
groups = ["default", "build"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
content_hash = "sha256:e744505d4be91a30830dd1d57d956a6c8775ea75385351b3f4c0d29faddd9ce3"
content_hash = "sha256:292c5ea319597e3539895c1ac50004c884c5d46edd5f7b195ede79156558feab"
[[metadata.targets]]
requires_python = ">=3.11"
@ -63,7 +63,7 @@ files = [
[[package]]
name = "obsws-python"
version = "1.8.0"
version = "1.7.2"
requires_python = ">=3.9"
summary = "A Python SDK for OBS Studio WebSocket v5.0"
groups = ["default"]
@ -72,8 +72,8 @@ dependencies = [
"websocket-client",
]
files = [
{file = "obsws_python-1.8.0-py3-none-any.whl", hash = "sha256:537bde416e149b6f59e0b2f31761d4a40329feafec171bde6fc1346ab8516e28"},
{file = "obsws_python-1.8.0.tar.gz", hash = "sha256:e082894f80deb0836861fdc3c222e497308c8f66328da6075baba5b456a20971"},
{file = "obsws_python-1.7.2-py3-none-any.whl", hash = "sha256:acda31852ad9d7165de915b0603c13f6df527d3f61619970bf5fb562e300bc85"},
{file = "obsws_python-1.7.2.tar.gz", hash = "sha256:b5cdaad30fbe1f6d4787b6530048b9882f070c3ee7830abb6dad4a47f84d7fa0"},
]
[[package]]

View File

@ -1,12 +1,12 @@
[project]
name = "simple-recorder"
version = "0.5.0"
version = "0.3.5"
description = "A simple OBS recorder"
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
dependencies = [
"clypi>=1.8.1",
"FreeSimpleGUI>=5.2.0.post1",
"obsws-python>=1.8.0",
"obsws-python>=1.7.2",
]
requires-python = ">=3.11"
readme = "README.md"

View File

@ -1,48 +0,0 @@
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 Chapter(Command):
"""Create a chapter in the current recording."""
chapter_name: Positional[str] = arg(
help="Name of the chapter to create.",
prompt="Enter the name for the chapter.",
default="unnamed",
)
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
@override
async def run(self):
"""Run the chapter command."""
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 create a chapter."
)
# Allow OBS to set unnamed chapters (it will increment the name)
if self.chapter_name == "unnamed":
client.create_record_chapter()
else:
client.create_record_chapter(self.chapter_name)
print(f"Chapter {highlight(self.chapter_name)} created successfully.")
except (ConnectionRefusedError, TimeoutError):
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")
except obsws.error.OBSSDKRequestError as e:
if e.code == 702:
raise SimpleRecorderError(
"Unable to create chapter, please check your OBS settings."
)
else:
raise SimpleRecorderError(f"Error: {e}")

View File

@ -3,16 +3,16 @@ import logging
from clypi import ClypiConfig, ClypiException, Command, arg, configure
from typing_extensions import override
from .chapter import Chapter
from .directory import Directory
from .errors import SimpleRecorderError
from .gui import SimpleRecorderWindow
from .pause import Pause
from .resume import Resume
from .split import Split
from .start import Start
from .stop import Stop
logger = logging.getLogger(__name__)
config = ClypiConfig(
nice_errors=(SimpleRecorderError,),
)
@ -37,11 +37,8 @@ def theme_parser(value: str) -> str:
return value
SUBCOMMANDS = Start | Stop | Pause | Resume | Split | Chapter | Directory
class SimpleRecorder(Command):
subcommand: SUBCOMMANDS | None = None
subcommand: Start | Stop | Pause | Resume | Directory | None = None
host: str = arg(default="localhost", env="OBS_HOST", help="OBS WebSocket host")
port: int = arg(default=4455, env="OBS_PORT", help="OBS WebSocket port")
password: str | None = arg(
@ -55,20 +52,17 @@ class SimpleRecorder(Command):
)
debug: bool = arg(
default=False,
env="DEBUG",
help="Enable debug logging",
hidden=True,
)
@override
async def pre_run_hook(self):
if self.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.disable())
@override
async def run(self):
"""Run the Simple Recorder GUI."""
if self.debug:
logging.basicConfig(level=logging.DEBUG)
window = SimpleRecorderWindow(self.host, self.port, self.password, self.theme)
await window.run()

View File

@ -3,12 +3,10 @@ import logging
import FreeSimpleGUI as fsg
import obsws_python as obsws
from .chapter import Chapter
from .directory import Directory
from .errors import SimpleRecorderError
from .pause import Pause
from .resume import Resume
from .split import Split
from .start import Start
from .stop import Stop
@ -96,10 +94,8 @@ class SimpleRecorderWindow(fsg.Window):
self["Stop Recording"].bind("<Return>", " || RETURN")
self["Pause Recording"].bind("<Return>", " || RETURN")
self["Resume Recording"].bind("<Return>", " || RETURN")
self["Split Recording"].bind("<Return>", " || RETURN")
self["Add Chapter"].bind("<Return>", " || RETURN")
self["Add Chapter"].bind("<Shift-Return>", " || SHIFT-RETURN")
self["-FILENAME-"].bind("<KeyPress>", " || KEYPRESS")
self["-FILENAME-"].update(select=True)
self["Add Chapter"].bind("<FocusIn>", " || FOCUS")
self["Add Chapter"].bind("<Enter>", " || FOCUS")
@ -111,8 +107,6 @@ class SimpleRecorderWindow(fsg.Window):
self["-UPDATE-"].bind("<Return>", " || RETURN")
async def run(self):
chapter_name = "unnamed"
while True:
event, values = self.read()
self.logger.debug(f"Event: {event}, Values: {values}")
@ -183,45 +177,17 @@ class SimpleRecorderWindow(fsg.Window):
else:
self["-OUTPUT-RECORDER-"].update("", text_color="white")
case ["Split Recording"] | ["Split Recording", "RETURN"]:
try:
await Split(
host=self.host, port=self.port, password=self.password
).run()
self["-OUTPUT-RECORDER-"].update(
"Recording split successfully", text_color="green"
)
except SimpleRecorderError as e:
self["-OUTPUT-RECORDER-"].update(
f"Error: {e.raw_message}", text_color="red"
)
case ["Add Chapter", "RIGHT_CLICK" | "SHIFT-RETURN"]:
chapter_name = fsg.popup_get_text(
case ["Add Chapter", "RIGHT_CLICK"]:
_ = fsg.popup_get_text(
"Enter chapter name:",
"Add Chapter",
default_text="unnamed",
)
case ["Add Chapter"] | ["Add Chapter", "RETURN"]:
try:
await Chapter(
chapter_name=chapter_name,
host=self.host,
port=self.port,
password=self.password,
).run()
self["-OUTPUT-RECORDER-"].update(
f"Chapter {chapter_name if chapter_name else 'unnamed'} added successfully",
text_color="green",
)
except SimpleRecorderError:
fsg.popup_error(
"Unable to create chapter, please check your OBS settings.\n"
"Note, currently only Hybrid MP4 is supported for chapters.",
title="Chapter Error",
keep_on_top=True,
)
case ["Split Recording" | "Add Chapter"]:
self["-OUTPUT-RECORDER-"].update(
"This feature is not implemented yet", text_color="orange"
)
case ["-GET-CURRENT-"] | ["-GET-CURRENT-", "RETURN"]:
try:

View File

@ -1,36 +0,0 @@
import obsws_python as obsws
from clypi import Command, arg
from typing_extensions import override
from .errors import SimpleRecorderError
class Split(Command):
"""Split the current recording into a new file."""
host: str = arg(inherited=True)
port: int = arg(inherited=True)
password: str = arg(inherited=True)
@override
async def run(self):
"""Run the split command."""
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 split.")
client.split_record_file()
print("Recording split successfully.")
except (ConnectionRefusedError, TimeoutError):
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")
except obsws.error.OBSSDKRequestError as e:
if e.code == 702:
raise SimpleRecorderError(
"Unable to split file, please check your OBS settings."
)
else:
raise SimpleRecorderError(f"Error: {e.code} - {e.message}")

View File

@ -3,6 +3,7 @@ from clypi import Command, arg
from typing_extensions import override
from .errors import SimpleRecorderError
from .styler import highlight
class Stop(Command):
@ -23,6 +24,6 @@ class Stop(Command):
raise SimpleRecorderError("Recording is not active.")
client.stop_record()
print("Recording stopped successfully.")
print(highlight("Recording stopped successfully."))
except (ConnectionRefusedError, TimeoutError):
raise SimpleRecorderError("Failed to connect to OBS. Is it running?")