Initial pass at getting all the scripts and menus working with the new everything in home setup. Also unify speech settings. Not sure why I thought separate speech settings for all menus was a good idea lol.

This commit is contained in:
Storm Dragon
2026-04-28 18:21:43 -04:00
parent 20811bba1e
commit 1063f21c43
13 changed files with 294 additions and 305 deletions
+28 -91
View File
@@ -3,51 +3,28 @@
# Self-voiced Speech Rate Configuration Menu
import os
import sys
import time
import curses
import speechd # Python bindings for Speech Dispatcher
import re
import subprocess
from stormux_speech_settings import (
SPEECHD_CONFIG,
FEX_SPEECHD_CONFIG,
SpeechSettings,
load_speech_settings,
save_speech_settings,
update_speechd_config_content as update_shared_speechd_config_content,
write_speechd_config,
)
def update_speechd_config_content(content, rate, volume, pitch):
"""Return speechd.conf content with updated default voice parameters."""
newContent = content
replacements = (
("DefaultRate", rate),
("DefaultVolume", volume),
("DefaultPitch", pitch),
return update_shared_speechd_config_content(
content,
SpeechSettings(rate=rate, volume=volume, pitch=pitch),
)
for settingName, settingValue in replacements:
activePattern = rf'^(\s*){settingName}\s+(-?\d+)'
commentedPattern = rf'^(\s*)#\s*{settingName}\s+(-?\d+)'
replacement = rf'\1{settingName} {settingValue}'
if re.search(activePattern, newContent, re.MULTILINE):
newContent = re.sub(
activePattern,
replacement,
newContent,
flags=re.MULTILINE,
)
else:
newContent = re.sub(
commentedPattern,
replacement,
newContent,
flags=re.MULTILINE,
)
return newContent
def get_writable_config_targets(configTargets):
"""Return existing config paths to update, preserving order."""
return [configPath for configPath in configTargets if os.path.exists(configPath)]
class SpeechRateMenu:
def __init__(self, title="Speech Configuration"):
@@ -59,11 +36,8 @@ class SpeechRateMenu:
self.modes = ["Rate", "Volume", "Pitch"]
self.stdscr = None
self.cursesInitialized = False # Flag to track if curses has been initialized
self.configFile = "/etc/speech-dispatcher/speechd.conf"
self.configTargets = [
self.configFile,
os.path.expanduser("~/.fex-emu/RootFS/ArchLinux/etc/speech-dispatcher/speechd.conf"),
]
self.configFile = str(SPEECHD_CONFIG)
self.configTargets = [SPEECHD_CONFIG, FEX_SPEECHD_CONFIG]
# Load current settings from config FIRST
self.load_current_settings()
@@ -90,35 +64,10 @@ class SpeechRateMenu:
def load_current_settings(self):
"""Load the current default settings from speechd.conf"""
try:
with open(self.configFile, 'r') as f:
content = f.read()
# Load Rate
activeMatch = re.search(r'^\s*DefaultRate\s+(-?\d+)', content, re.MULTILINE)
if activeMatch:
self.currentRate = int(activeMatch.group(1))
else:
commentedMatch = re.search(r'^\s*#\s*DefaultRate\s+(-?\d+)', content, re.MULTILINE)
if commentedMatch:
self.currentRate = int(commentedMatch.group(1))
# Load Volume
activeMatch = re.search(r'^\s*DefaultVolume\s+(-?\d+)', content, re.MULTILINE)
if activeMatch:
self.currentVolume = int(activeMatch.group(1))
else:
commentedMatch = re.search(r'^\s*#\s*DefaultVolume\s+(-?\d+)', content, re.MULTILINE)
if commentedMatch:
self.currentVolume = int(commentedMatch.group(1))
# Load Pitch
activeMatch = re.search(r'^\s*DefaultPitch\s+(-?\d+)', content, re.MULTILINE)
if activeMatch:
self.currentPitch = int(activeMatch.group(1))
else:
commentedMatch = re.search(r'^\s*#\s*DefaultPitch\s+(-?\d+)', content, re.MULTILINE)
if commentedMatch:
self.currentPitch = int(commentedMatch.group(1))
settings = load_speech_settings(self.configFile)
self.currentRate = settings.rate
self.currentVolume = settings.volume
self.currentPitch = settings.pitch
except Exception:
# If loading fails, we'll use default values
@@ -127,26 +76,14 @@ class SpeechRateMenu:
def save_settings_to_config(self):
"""Save the current settings to the speech-dispatcher config file"""
try:
for configPath in get_writable_config_targets(self.configTargets):
with open(configPath, 'r') as f:
content = f.read()
newContent = update_speechd_config_content(
content,
self.currentRate,
self.currentVolume,
self.currentPitch,
)
tempFile = f"/tmp/{os.path.basename(configPath)}.new"
with open(tempFile, 'w') as f:
f.write(newContent)
subprocess.run(
["sudo", "mv", tempFile, configPath],
check=True,
)
save_speech_settings(
SpeechSettings(
rate=self.currentRate,
volume=self.currentVolume,
pitch=self.currentPitch,
),
self.configTargets,
)
return True
except Exception:
return False
@@ -230,7 +167,7 @@ class SpeechRateMenu:
def confirm_saved_settings(self):
"""Restart speechd, announce success, and wait for confirmation."""
subprocess.run(
["sudo", "killall", "speech-dispatcher"],
["killall", "speech-dispatcher"],
check=False,
)
time.sleep(1)