diff --git a/rewind/autostart.py b/rewind/autostart.py new file mode 100644 index 0000000..b98f93a --- /dev/null +++ b/rewind/autostart.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +import os +import platform +import shutil +import subprocess + +from pathlib import Path + +APP_NAME = "rewind-daemon" + +def _find_executable(): + path = shutil.which(APP_NAME) + if not path: + raise RuntimeError(f"{APP_NAME} not found in PATH") + return path + +def _run(cmd: list[str]): + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + if result.returncode != 0: + raise RuntimeError(f"Command failed: {' '.join(cmd)}\n{result.stderr}") + return result + +def _install_linux(program_path: str): + systemd_dir = Path.home() / ".config/systemd/user" + systemd_dir.mkdir(parents=True, exist_ok=True) + + obs_service = systemd_dir / "obs.service" + daemon_service = systemd_dir / "rewind-daemon.service" + + if obs_service.exists(): + print("obs.service already exists, skipping creation") + else: + obs_service.write_text("""[Unit] +Description=OBS Studio +After=graphical-session.target +Wants=graphical-session.target + +[Service] +ExecStart=obs --minimize-to-tray +Restart=on-failure +RestartSec=3 + +[Install] +WantedBy=default.target +""") + + if daemon_service.exists(): + print("rewind-daemon.service already exists, skipping creation") + else: + daemon_service.write_text(f"""[Unit] +Description=Rewind Daemon +After=obs.service +Requires=obs.service + +[Service] +ExecStart={program_path} +Restart=always +RestartSec=5 +Environment=PYTHONUNBUFFERED=1 + +[Install] +WantedBy=default.target +""") + + _run(["systemctl", "--user", "daemon-reload"]) + + _run(["systemctl", "--user", "enable", "obs.service"]) + _run(["systemctl", "--user", "enable", "rewind-daemon.service"]) + + _run(["systemctl", "--user", "start", "obs.service"]) + _run(["systemctl", "--user", "start", "rewind-daemon.service"]) + + print("Installed and started OBS + rewind-daemon via systemd") + +def install(): + system = platform.system() + program_path = _find_executable() + + if system == "Linux": + _install_linux(program_path) + else: + raise RuntimeError(f"Autostart on OS {system} not compatible or not implemented") + +if __name__ == "__main__": + install() \ No newline at end of file diff --git a/rewind/cli.py b/rewind/cli.py index 4a791d9..3a42995 100755 --- a/rewind/cli.py +++ b/rewind/cli.py @@ -3,6 +3,7 @@ import sys import argparse from rewind.core import clip, mark, save, print_markers +from rewind.autostart import install def build_clip_parser(subparsers: argparse._SubParsersAction) -> None: clip_parser = subparsers.add_parser("clip", help="Clips the last 'x' seconds") @@ -41,6 +42,13 @@ def build_mark_parser(subparsers: argparse._SubParsersAction) -> None: def build_list_parser(subparsers: argparse._SubParsersAction) -> None: list_parser = subparsers.add_parser("list", help="List all markers in the recording") +def build_install_parser(subparsers: argparse._SubParsersAction): + subparsers.add_parser( + "install", + help="Enable background recording daemon", + description="Install and enable the rewind daemon using system autostart." + ) + def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="rewind", @@ -53,6 +61,7 @@ def build_parser() -> argparse.ArgumentParser: build_mark_parser(sub) build_list_parser(sub) build_save_parser(sub) + build_install_parser(sub) return parser @@ -69,6 +78,8 @@ def main(argv=None) -> int: print_markers() elif args.command == "save": save(args.start, args.end) + elif args.command == "install": + install() else: parser.error("Unknown command") except Exception as e: