Made settings configureable without changing code
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
replays
|
||||
temp_mic_audio.wav
|
||||
temp_mic_audio.wav
|
||||
config.json
|
||||
45
README.md
45
README.md
@@ -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
35
config.example.json
Normal 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
125
main.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user