diff --git a/usr/local/bin/speechd_rate.py b/usr/local/bin/speechd_rate.py index f62d17d..bf236ab 100755 --- a/usr/local/bin/speechd_rate.py +++ b/usr/local/bin/speechd_rate.py @@ -11,6 +11,39 @@ import speechd # Python bindings for Speech Dispatcher import re import subprocess +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), + ) + + 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 + + class SpeechRateMenu: def __init__(self, title="Speech Configuration"): self.title = title @@ -22,6 +55,10 @@ class SpeechRateMenu: 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"), + ] # Load current settings from config FIRST self.load_current_settings() @@ -85,72 +122,26 @@ class SpeechRateMenu: def save_settings_to_config(self): """Save the current settings to the speech-dispatcher config file""" try: - # We need to use sudo to modify the system config file - # This assumes the user has sudo privileges or the script is run as root - - # Create a temporary file with the modified content - with open(self.configFile, 'r') as f: - content = f.read() - - newContent = content - - # Handle DefaultRate - if re.search(r'^\s*DefaultRate\s+', newContent, re.MULTILINE): - newContent = re.sub( - r'^(\s*)DefaultRate\s+(-?\d+)', - r'\1DefaultRate ' + str(self.currentRate), - newContent, - flags=re.MULTILINE + for configPath in self.configTargets: + with open(configPath, 'r') as f: + content = f.read() + + newContent = update_speechd_config_content( + content, + self.currentRate, + self.currentVolume, + self.currentPitch, ) - else: - newContent = re.sub( - r'^(\s*)#\s*DefaultRate\s+(-?\d+)', - r'\1DefaultRate ' + str(self.currentRate), - newContent, - flags=re.MULTILINE + + 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, ) - - # Handle DefaultVolume - if re.search(r'^\s*DefaultVolume\s+', newContent, re.MULTILINE): - newContent = re.sub( - r'^(\s*)DefaultVolume\s+(-?\d+)', - r'\1DefaultVolume ' + str(self.currentVolume), - newContent, - flags=re.MULTILINE - ) - else: - newContent = re.sub( - r'^(\s*)#\s*DefaultVolume\s+(-?\d+)', - r'\1DefaultVolume ' + str(self.currentVolume), - newContent, - flags=re.MULTILINE - ) - - # Handle DefaultPitch - if re.search(r'^\s*DefaultPitch\s+', newContent, re.MULTILINE): - newContent = re.sub( - r'^(\s*)DefaultPitch\s+(-?\d+)', - r'\1DefaultPitch ' + str(self.currentPitch), - newContent, - flags=re.MULTILINE - ) - else: - newContent = re.sub( - r'^(\s*)#\s*DefaultPitch\s+(-?\d+)', - r'\1DefaultPitch ' + str(self.currentPitch), - newContent, - flags=re.MULTILINE - ) - - # Write to a temporary file - tempFile = "/tmp/speechd.conf.new" - with open(tempFile, 'w') as f: - f.write(newContent) - - # Use sudo to move the file to the correct location - cmd = f"sudo mv {tempFile} {self.configFile}" - subprocess.run(cmd, shell=True, check=True) - + return True except Exception: return False @@ -404,7 +395,8 @@ class SpeechRateMenu: break # Exit the loop after saving elif key == 27 or key == ord('q') or key == ord('Q'): # Esc or Q - self.speak("Exiting speech configuration.") + self.speak("Speech settings discarded.") + time.sleep(3) break except Exception: