Made settings configureable without changing code

This commit is contained in:
Space-Banane
2026-01-16 21:55:05 +01:00
parent 5d6f678e77
commit f053ce39e6
4 changed files with 159 additions and 49 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
replays
temp_mic_audio.wav
temp_mic_audio.wav
config.json

View File

@@ -6,14 +6,36 @@ Why not? Try it out. It's fun.
Did not see how you died in that round? Just say "replay that" and see the last 30 seconds of your gameplay in a little overlay box that does not disturb your game.
## Configuration
Before starting, configure the application by creating a `config.json` file:
1. Copy the example configuration:
```sh
cp config.example.json config.json
```
2. Edit `config.json` to customize your settings:
- **directories.watch_dir**: Where OBS saves replay buffers (e.g., `E:\OBS`)
- **directories.moveto_dir**: Where processed replays are stored (default: `./replays`)
- **server.port**: HTTP server port for serving video files (default: `8000`)
- **server.websocket_port**: WebSocket port for Electron communication (default: `8001`)
- **replay.length_seconds**: Duration of replays in seconds (default: `20`)
- **replay.default_location**: Overlay position (`center`, `top_left`, `bottom_left`, `top_right`)
- **replay.default_size**: Overlay size from 1 (smallest) to 10 (largest)
- **voice_recognition.enabled**: Enable/disable voice commands (default: `false`)
- **hotkey.enabled**: Enable/disable hotkey (default: `true`)
- **hotkey.key**: Hotkey to trigger replays (default: `pagedown`)
- **commands**: Customize voice command phrases for activation, stop, replay last, and clear
## Start the thing
1. Clone this repository.
2. Install Electron globally (if you don't have it):
2. Configure the application (see Configuration section above).
3. Install Electron globally (if you don't have it):
```sh
npm i -g electron
```
3. Open multiple terminals and run the following commands:
4. Open multiple terminals and run the following commands:
1. **Terminal 1:** Start the Python server that listens for commands and communicates with OBS & the Electron app:
```sh
python main.py
@@ -22,23 +44,26 @@ Did not see how you died in that round? Just say "replay that" and see the last
```sh
npx electron electron-main.js
```
3. **Terminal 3:** Serve the replays folder on port 8000:
3. **Terminal 3:** Serve the replays folder on the configured port (default 8000):
```sh
npx serve ./replays -p 8000
```
## Usage
1. Make sure OBS is running with a scene that has your game or desktop.
2. Make sure the everything is running.
2. Make sure everything is running.
3. Make sure you have the WebSocket server configured correctly, check the code or change the port in OBS to 4455 and disable authentication.
4. Make sure the Replay Buffer is enabled in OBS and set to the same length as in `main.py` (default 30 seconds), else ffmpeg will clip to the duration set in the `main.py` script.
5. Say "replay that" (you can change the hotword in `main.py`) to save the last X seconds of gameplay.
4. Make sure the Replay Buffer is enabled in OBS and set to the same length as configured in `config.json` (default 20 seconds), else ffmpeg will clip to the duration set in your configuration.
5. Press your configured hotkey (default: Page Down) or say "replay that" to save the last X seconds of gameplay.
## Other commands
- **Activation:** Say "instant replay" to save the last X seconds.
- **Stop:** Say "stop replay" to hide the replay overlay.
- **Replay Last:** Say "replay last" to show the most recent replay.
- **Clear Replays:** Say "clear replays" to delete all saved clips.
- **Hotkey Toggle:** Press your configured hotkey (default: Page Down) to trigger or stop replays
- **Activation (Voice):** Say "instant replay" to save the last X seconds
- **Stop (Voice):** Say "stop replay" to hide the replay overlay
- **Replay Last (Voice):** Say "replay last" to show the most recent replay
- **Clear Replays (Voice):** Say "clear replays" to delete all saved clips
All voice commands can be customized in `config.json`.
## Requirements
- OBS Studio with a working Websocket Server

35
config.example.json Normal file
View File

@@ -0,0 +1,35 @@
{
"directories": {
"watch_dir": "E:\\OBS",
"moveto_dir": "./replays"
},
"server": {
"port": 8000,
"websocket_port": 8001
},
"replay": {
"length_seconds": 20,
"default_location": "center",
"default_size": 5
},
"voice_recognition": {
"enabled": false,
"sample_rate": 16000,
"duration": 4,
"calibration_duration": 2
},
"live_display": {
"enabled": false,
"interval": 0.5
},
"commands": {
"activation": ["instant replay", "save replay", "capture replay", "replay that"],
"stop": ["stop replay", "stop video", "hide replay"],
"replay_last": ["replay last", "show last replay", "play last", "replay it again"],
"clear_replays": ["clear replays", "delete all replays", "nuke replays", "remove all clips"]
},
"hotkey": {
"enabled": true,
"key": "pagedown"
}
}

125
main.py
View File

@@ -30,6 +30,74 @@ except ImportError:
psutil = None
def load_config():
"""Load configuration from config.json with fallback to defaults."""
default_config = {
"directories": {
"watch_dir": r"E:\OBS",
"moveto_dir": "./replays"
},
"server": {
"port": 8000,
"websocket_port": 8001
},
"replay": {
"length_seconds": 20,
"default_location": "center",
"default_size": 5
},
"voice_recognition": {
"enabled": False,
"sample_rate": 16000,
"duration": 4,
"calibration_duration": 2
},
"live_display": {
"enabled": False,
"interval": 0.5
},
"commands": {
"activation": ["instant replay", "save replay", "capture replay", "replay that"],
"stop": ["stop replay", "stop video", "hide replay"],
"replay_last": ["replay last", "show last replay", "play last", "replay it again"],
"clear_replays": ["clear replays", "delete all replays", "nuke replays", "remove all clips"]
},
"hotkey": {
"enabled": True,
"key": "pagedown"
}
}
config_path = "config.json"
if os.path.exists(config_path):
try:
with open(config_path, "r") as f:
user_config = json.load(f)
# Merge user config with defaults (deep merge)
def deep_merge(default, user):
result = default.copy()
for key, value in user.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = deep_merge(result[key], value)
else:
result[key] = value
return result
config = deep_merge(default_config, user_config)
print(f"Configuration loaded from {config_path}")
return config
except Exception as e:
print(f"Error loading config.json: {e}. Using default configuration.")
return default_config
else:
print(f"No {config_path} found. Using default configuration.")
print(f"Tip: Copy config.example.json to config.json to customize settings.")
return default_config
# Load configuration
config = load_config()
def is_obs_running():
"""Check if OBS Studio is running."""
if not PSUTIL_AVAILABLE:
@@ -73,50 +141,31 @@ def set_process_priority():
print(f"Unable to adjust process priority: {exc}")
# Directories
WATCH_DIR = r"E:\OBS"
MOVETO_DIR = os.path.abspath("./replays")
# Extract configuration values
WATCH_DIR = config["directories"]["watch_dir"]
MOVETO_DIR = os.path.abspath(config["directories"]["moveto_dir"])
# Server Ports
SERVER_PORT = 8000
WEBSOCKET_PORT = 8001
SERVER_PORT = config["server"]["port"]
WEBSOCKET_PORT = config["server"]["websocket_port"]
# Replay Settings
REPLAY_LENGTH_SECONDS = 20
DEFAULT_LOCATION = "center" # options: 'top_left', 'bottom_left', 'top_right', 'center'
DEFAULT_SIZE = 5 # 1 (smallest) to 10 (largest)
REPLAY_LENGTH_SECONDS = config["replay"]["length_seconds"]
DEFAULT_LOCATION = config["replay"]["default_location"]
DEFAULT_SIZE = config["replay"]["default_size"]
# Voice Recognition Settings
VOICE_ENABLED = False
SAMPLE_RATE = 16000
DURATION = 4 # seconds to record per command attempt
CALIBRATION_DURATION = 2 # seconds for ambient calibration
VOICE_ENABLED = config["voice_recognition"]["enabled"]
SAMPLE_RATE = config["voice_recognition"]["sample_rate"]
DURATION = config["voice_recognition"]["duration"]
CALIBRATION_DURATION = config["voice_recognition"]["calibration_duration"]
# Live Display Settings
LIVE_DISPLAY_ENABLED = False # Enable periodic status updates during replay
LIVE_DISPLAY_INTERVAL = 0.5 # Seconds between each update (e.g., 0.1 = 10 updates per second)
LIVE_DISPLAY_ENABLED = config["live_display"]["enabled"]
LIVE_DISPLAY_INTERVAL = config["live_display"]["interval"]
# Commands
ACTIVATION_COMMANDS = ["instant replay", "save replay", "capture replay", "replay that"]
STOP_COMMANDS = ["stop replay", "stop video", "hide replay"]
REPLAY_LAST_COMMANDS = [
"replay last",
"show last replay",
"play last",
"replay it again",
]
CLEAR_REPLAYS_COMMANDS = [
"clear replays",
"delete all replays",
"nuke replays",
"remove all clips",
]
ACTIVATION_COMMANDS = config["commands"]["activation"]
STOP_COMMANDS = config["commands"]["stop"]
REPLAY_LAST_COMMANDS = config["commands"]["replay_last"]
CLEAR_REPLAYS_COMMANDS = config["commands"]["clear_replays"]
# Hotkey Settings
HOTKEY = {
"enabled": True,
"key": "pagedown", # Change to your preferred key
}
HOTKEY = config["hotkey"]
# Replay state tracking
is_replaying = threading.Event()