diff --git a/flatpak/com.mikeasoft.pied.yaml b/flatpak/com.mikeasoft.pied.yaml index 7ac91c6..b2395a6 100644 --- a/flatpak/com.mikeasoft.pied.yaml +++ b/flatpak/com.mikeasoft.pied.yaml @@ -11,7 +11,7 @@ finish-args: - --device=dri - --socket=pulseaudio - --share=network - - --filesystem=home + - --filesystem=xdg-config/speech-dispathcer:create - --talk-name=org.freedesktop.Flatpak modules: - name: Pied diff --git a/lib/voice_buttons.dart b/lib/voice_buttons.dart index 0862a20..a116514 100644 --- a/lib/voice_buttons.dart +++ b/lib/voice_buttons.dart @@ -48,60 +48,95 @@ class _VoiceButtonsState extends State { } } - void setSDConfig() async { + Future setSDConfig() async { Directory confDir = Directory(path.join(getHome()!, ".config/speech-dispatcher")); - Directory? originalConfigDir; - if (confDir.existsSync()) { - File sdConfig = File(path.join(confDir.path, "speechd.conf")); - if (sdConfig.existsSync()) { - if (sdConfig - .readAsStringSync() - .contains("THIS CONFIG WAS GENERATED BY PIED")) { - return; - } - } - DateTime now = DateTime.now(); - Directory newDir; - if (isSnap()) { - Directory origDir = - Directory(path.join(getHome()!, ".config/speech-dispatcher.orig")); - if (!origDir.existsSync()) { - origDir.createSync(); - } - newDir = Directory( - "${confDir.path}.orig/${now.year}-${now.month}-${now.day}"); - } else { - newDir = Directory( - "${confDir.path}.orig.${now.year}-${now.month}-${now.day}"); + + // Ensure the main config directory and subdirectories exist + if (!confDir.existsSync()) { + confDir.createSync(recursive: true); + } + Directory modulesDir = Directory(path.join(confDir.path, "modules")); + if (!modulesDir.existsSync()) { + modulesDir.createSync(recursive: true); + } + Directory clientsDir = Directory(path.join(confDir.path, "clients")); + if (!clientsDir.existsSync()) { + clientsDir.createSync(recursive: true); + } + + File sdConfig = File(path.join(confDir.path, "speechd.conf")); + File piperConfig = File(path.join(modulesDir.path, "piper.conf")); + + DateTime now = DateTime.now(); + String timestamp = + "${now.year}-${now.month}-${now.day}-${now.hour}-${now.minute}-${now.second}"; + + File? sdBackup; + File? piperBackup; + bool sdChanged = false; + + // Check/Backup speechd.conf + // If it exists and DOES NOT contain our signature, back it up. + if (sdConfig.existsSync()) { + if (!sdConfig.readAsStringSync().contains("THIS CONFIG WAS GENERATED BY PIED")) { + sdBackup = File("${sdConfig.path}.bak-$timestamp"); + sdConfig.renameSync(sdBackup.path); + + // We only create new config if we moved the old one or it didn't exist + sdConfig.createSync(); + sdConfig.writeAsString(sdConfigTemplate); + sdChanged = true; } - if (newDir.existsSync()) { - newDir.deleteSync(recursive: true); + } else { + // Create fresh if didn't exist + sdConfig.createSync(); + sdConfig.writeAsString(sdConfigTemplate); + sdChanged = true; + } + + // if not generated by pied -> back up + if (piperConfig.existsSync()) { + if (!piperConfig.readAsStringSync().contains("THIS CONFIG WAS GENERATED BY PIED")) { + piperBackup = File("${piperConfig.path}.bak-$timestamp"); + piperConfig.renameSync(piperBackup.path); } - confDir.renameSync(newDir.path); - originalConfigDir = newDir; } - confDir.createSync(); - Directory(path.join(confDir.path, "clients")).create(); - Directory(path.join(confDir.path, "modules")).create(); - File sdConfig = File(path.join(confDir.path, "speechd.conf")); - sdConfig.createSync(); - sdConfig.writeAsString(sdConfigTemplate); - restartSD(); - Timer(const Duration(seconds: 2), () { - confirmConfigChange(originalConfigDir); - }); + + // if changed config -> ask for confirmation + if (sdChanged) { + restartSD(); + Timer(const Duration(seconds: 2), () { + confirmConfigChange(sdBackup, piperBackup); + }); + } } - Future revertConfig(Directory? originalConfigDir) async { + Future revertConfig(File? sdBackup, File? piperBackup) async { Directory confDir = Directory(path.join(getHome()!, ".config/speech-dispatcher")); - confDir.deleteSync(recursive: true); - if (originalConfigDir != null) { - originalConfigDir.rename(confDir.path); + File sdConfig = File(path.join(confDir.path, "speechd.conf")); + File piperConfig = File(path.join(confDir.path, "modules/piper.conf")); + + // undo the Pied configuration + if (sdConfig.existsSync()) { + sdConfig.deleteSync(); + } + if (piperConfig.existsSync()) { + piperConfig.deleteSync(); + } + + // restore backups + if (sdBackup != null && sdBackup.existsSync()) { + sdBackup.renameSync(sdConfig.path); + } + if (piperBackup != null && piperBackup.existsSync()) { + piperBackup.renameSync(piperConfig.path); } + widget.onCurrentVoiceChanged(""); restartSD(); + Timer(const Duration(seconds: 2), () { showDialog( context: context, @@ -136,13 +171,13 @@ class _VoiceButtonsState extends State { }); } - Future confirmConfigChange(Directory? originalConfigDir) async { + Future confirmConfigChange(File? sdBackup, File? piperBackup) async { return showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return ConfirmationDialog(onRevert: () { - revertConfig(originalConfigDir); + revertConfig(sdBackup, piperBackup); }); }); } @@ -161,12 +196,14 @@ class _VoiceButtonsState extends State { enabled: true, child: ElevatedButton( onPressed: () async { - setSDConfig(); + await setSDConfig(); + final Directory appDir = await getDataDir(); Directory modelDir = Directory(path.join(appDir.path, "models")); File modelConf = File(path.join(getHome()!, ".config/speech-dispatcher/modules/piper.conf")); + String configString = modelTemplate; configString = configString.replaceAll("PIPER_PATH", path.join(appDir.path, "piper", "piper")); @@ -178,7 +215,15 @@ class _VoiceButtonsState extends State { "LANGUAGE", widget.voiceData[1]); configString = configString.replaceAll( "SUBVOICE", widget.selectedSubVoice.toString()); - modelConf.writeAsString(configString); + + String header = "# THIS CONFIG WAS GENERATED BY PIED\n"; + + if (!modelConf.parent.existsSync()) { + modelConf.parent.createSync(recursive: true); + } + + // add pied signature to piper.conf + modelConf.writeAsString(header + configString); restartSD(); widget.onCurrentVoiceChanged(widget.voiceData[4]); widget.onCurrentSubVoiceChanged(