Made settings configureable without changing code
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
replays
|
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.
|
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
|
## Start the thing
|
||||||
|
|
||||||
1. Clone this repository.
|
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
|
```sh
|
||||||
npm i -g electron
|
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:
|
1. **Terminal 1:** Start the Python server that listens for commands and communicates with OBS & the Electron app:
|
||||||
```sh
|
```sh
|
||||||
python main.py
|
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
|
```sh
|
||||||
npx electron electron-main.js
|
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
|
```sh
|
||||||
npx serve ./replays -p 8000
|
npx serve ./replays -p 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
1. Make sure OBS is running with a scene that has your game or desktop.
|
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.
|
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.
|
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. Say "replay that" (you can change the hotword in `main.py`) to save the last X seconds of gameplay.
|
5. Press your configured hotkey (default: Page Down) or say "replay that" to save the last X seconds of gameplay.
|
||||||
|
|
||||||
## Other commands
|
## Other commands
|
||||||
- **Activation:** Say "instant replay" to save the last X seconds.
|
- **Hotkey Toggle:** Press your configured hotkey (default: Page Down) to trigger or stop replays
|
||||||
- **Stop:** Say "stop replay" to hide the replay overlay.
|
- **Activation (Voice):** Say "instant replay" to save the last X seconds
|
||||||
- **Replay Last:** Say "replay last" to show the most recent replay.
|
- **Stop (Voice):** Say "stop replay" to hide the replay overlay
|
||||||
- **Clear Replays:** Say "clear replays" to delete all saved clips.
|
- **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
|
## Requirements
|
||||||
- OBS Studio with a working Websocket Server
|
- 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
|
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():
|
def is_obs_running():
|
||||||
"""Check if OBS Studio is running."""
|
"""Check if OBS Studio is running."""
|
||||||
if not PSUTIL_AVAILABLE:
|
if not PSUTIL_AVAILABLE:
|
||||||
@@ -73,50 +141,31 @@ def set_process_priority():
|
|||||||
print(f"Unable to adjust process priority: {exc}")
|
print(f"Unable to adjust process priority: {exc}")
|
||||||
|
|
||||||
|
|
||||||
# Directories
|
# Extract configuration values
|
||||||
WATCH_DIR = r"E:\OBS"
|
WATCH_DIR = config["directories"]["watch_dir"]
|
||||||
MOVETO_DIR = os.path.abspath("./replays")
|
MOVETO_DIR = os.path.abspath(config["directories"]["moveto_dir"])
|
||||||
|
|
||||||
# Server Ports
|
SERVER_PORT = config["server"]["port"]
|
||||||
SERVER_PORT = 8000
|
WEBSOCKET_PORT = config["server"]["websocket_port"]
|
||||||
WEBSOCKET_PORT = 8001
|
|
||||||
|
|
||||||
# Replay Settings
|
REPLAY_LENGTH_SECONDS = config["replay"]["length_seconds"]
|
||||||
REPLAY_LENGTH_SECONDS = 20
|
DEFAULT_LOCATION = config["replay"]["default_location"]
|
||||||
DEFAULT_LOCATION = "center" # options: 'top_left', 'bottom_left', 'top_right', 'center'
|
DEFAULT_SIZE = config["replay"]["default_size"]
|
||||||
DEFAULT_SIZE = 5 # 1 (smallest) to 10 (largest)
|
|
||||||
|
|
||||||
# Voice Recognition Settings
|
VOICE_ENABLED = config["voice_recognition"]["enabled"]
|
||||||
VOICE_ENABLED = False
|
SAMPLE_RATE = config["voice_recognition"]["sample_rate"]
|
||||||
SAMPLE_RATE = 16000
|
DURATION = config["voice_recognition"]["duration"]
|
||||||
DURATION = 4 # seconds to record per command attempt
|
CALIBRATION_DURATION = config["voice_recognition"]["calibration_duration"]
|
||||||
CALIBRATION_DURATION = 2 # seconds for ambient calibration
|
|
||||||
|
|
||||||
# Live Display Settings
|
LIVE_DISPLAY_ENABLED = config["live_display"]["enabled"]
|
||||||
LIVE_DISPLAY_ENABLED = False # Enable periodic status updates during replay
|
LIVE_DISPLAY_INTERVAL = config["live_display"]["interval"]
|
||||||
LIVE_DISPLAY_INTERVAL = 0.5 # Seconds between each update (e.g., 0.1 = 10 updates per second)
|
|
||||||
|
|
||||||
# Commands
|
ACTIVATION_COMMANDS = config["commands"]["activation"]
|
||||||
ACTIVATION_COMMANDS = ["instant replay", "save replay", "capture replay", "replay that"]
|
STOP_COMMANDS = config["commands"]["stop"]
|
||||||
STOP_COMMANDS = ["stop replay", "stop video", "hide replay"]
|
REPLAY_LAST_COMMANDS = config["commands"]["replay_last"]
|
||||||
REPLAY_LAST_COMMANDS = [
|
CLEAR_REPLAYS_COMMANDS = config["commands"]["clear_replays"]
|
||||||
"replay last",
|
|
||||||
"show last replay",
|
|
||||||
"play last",
|
|
||||||
"replay it again",
|
|
||||||
]
|
|
||||||
CLEAR_REPLAYS_COMMANDS = [
|
|
||||||
"clear replays",
|
|
||||||
"delete all replays",
|
|
||||||
"nuke replays",
|
|
||||||
"remove all clips",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Hotkey Settings
|
HOTKEY = config["hotkey"]
|
||||||
HOTKEY = {
|
|
||||||
"enabled": True,
|
|
||||||
"key": "pagedown", # Change to your preferred key
|
|
||||||
}
|
|
||||||
|
|
||||||
# Replay state tracking
|
# Replay state tracking
|
||||||
is_replaying = threading.Event()
|
is_replaying = threading.Event()
|
||||||
|
|||||||
Reference in New Issue
Block a user