diff --git a/CHANGELOG.md b/CHANGELOG.md index a26885c..1d982a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ - Now you can play the audio files while they are processing. - While generating audio files, now it directly writes to audio file instead of RAM, which significantly reduces memory usage and prevents memory outage issues. - Added a better logic for detecting chapters from the epub, mentioned by @jefro108 in #33 +- Added a new option: `Reset to default settings`, allowing users to reset all settings to their default values. +- Added a new option: `Disable Kokoro's internet access`. This lets you prevent Kokoro from downloading models or voices from HuggingFace Hub, which can help avoid long waiting times if your computer is offline. +- HuggingFace Hub telemetry is now disabled by default for improved privacy. (HuggingFace Hub is used by Kokoro to download its models) - Potential fix for #37 and #38, where the program was becoming slow while processing large files. - Fixed `Open folder` and `Open file` buttons in the queue manager GUI. - Improvements in code structure. diff --git a/README.md b/README.md index 95cf045..ebdf5fc 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,8 @@ Here’s Abogen in action: in this demo, it processes ∼3,000 characters of tex | **Open temp directory** | Opens the temporary directory where converted text files are stored. | | **Clear temporary files** | Deletes temporary files created during the conversion or preview. | | **Check for updates at startup** | Automatically checks for updates when the program starts. | +| **Disable Kokoro's internet access** | Prevents Kokoro from downloading models or voices from HuggingFace Hub, useful for offline use. | +| **Reset to default settings** | Resets all settings to their default values. | ## `Voice Mixer` diff --git a/abogen/conversion.py b/abogen/conversion.py index 596d83e..a8da622 100644 --- a/abogen/conversion.py +++ b/abogen/conversion.py @@ -474,7 +474,7 @@ class ConversionThread(QThread): merged_out_file = sf.SoundFile(merged_out_path, "w", samplerate=24000, channels=1, format=self.output_format) ffmpeg_proc = None elif self.output_format == "m4b": - temp_wav_path = f"{base_filepath_no_ext}_temp.wav" + temp_wav_path = os.path.join(out_dir, f"temp_{base_name}{suffix}.wav") merged_out_file = sf.SoundFile(temp_wav_path, "w", samplerate=24000, channels=1, format="wav") ffmpeg_proc = None elif self.output_format == "opus": diff --git a/abogen/gui.py b/abogen/gui.py index 52d4c4d..e433788 100644 --- a/abogen/gui.py +++ b/abogen/gui.py @@ -2774,6 +2774,15 @@ class abogen(QWidget): # Add seperator" menu.addSeparator() + # Add "Disable Kokoro's internet access" option + disable_kokoro_action = QAction("Disable Kokoro's internet access", self) + disable_kokoro_action.setCheckable(True) + disable_kokoro_action.setChecked(self.config.get("disable_kokoro_internet", False)) + disable_kokoro_action.triggered.connect( + lambda checked: self.toggle_kokoro_internet_access(checked) + ) + menu.addAction(disable_kokoro_action) + # Add check for updates option check_updates_action = QAction("Check for updates at startup", self) check_updates_action.setCheckable(True) @@ -2781,6 +2790,11 @@ class abogen(QWidget): check_updates_action.triggered.connect(self.toggle_check_updates) menu.addAction(check_updates_action) + # Add "Reset to default settings" option + reset_defaults_action = QAction("Reset to default settings", self) + reset_defaults_action.triggered.connect(self.reset_to_default_settings) + menu.addAction(reset_defaults_action) + # Add about action about_action = QAction("About", self) about_action.triggered.connect(self.show_about_dialog) @@ -2793,6 +2807,50 @@ class abogen(QWidget): self.config["replace_single_newlines"] = enabled save_config(self.config) + def toggle_kokoro_internet_access(self, disabled): + reply = QMessageBox.question( + self, + "Restart Required", + "Changing Kokoro's internet access requires restarting the application.\nDo you want to continue?", + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No, + ) + if reply == QMessageBox.Yes: + self.config["disable_kokoro_internet"] = disabled + save_config(self.config) + try: + from PyQt5.QtCore import QProcess + import sys + QProcess.startDetached(sys.executable, sys.argv) + QApplication.quit() + except Exception as e: + QMessageBox.critical( + self, + "Restart Failed", + f"Failed to restart the application:\n{e}" + ) + + def reset_to_default_settings(self): + reply = QMessageBox.question( + self, + "Reset Settings", + "This will reset all settings to their default values and restart the application.\nDo you want to continue?", + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No, + ) + if reply == QMessageBox.Yes: + from abogen.utils import get_user_config_path + import sys + config_path = get_user_config_path() + try: + if os.path.exists(config_path): + os.remove(config_path) + from PyQt5.QtCore import QProcess + QProcess.startDetached(sys.executable, sys.argv) + QApplication.quit() + except Exception as e: + QMessageBox.critical(self, "Reset Error", f"Could not reset settings:\n{e}") + def reveal_config_in_explorer(self): """Open the configuration file location in file explorer.""" from abogen.utils import get_user_config_path diff --git a/abogen/main.py b/abogen/main.py index 6933249..3e94a31 100644 --- a/abogen/main.py +++ b/abogen/main.py @@ -1,3 +1,4 @@ +from json import load import os import sys import platform @@ -7,8 +8,19 @@ from PyQt5.QtCore import qInstallMessageHandler, QtMsgType # Add the directory to Python path sys.path.insert(0, os.path.join(os.path.dirname(__file__))) + +from abogen.utils import get_resource_path, load_config + +# Set Hugging Face Hub environment variables +os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1" # Disable Hugging Face telemetry +os.environ["HF_HUB_ETAG_TIMEOUT"] = "10" # Metadata request timeout (seconds) +os.environ["HF_HUB_DOWNLOAD_TIMEOUT"] = "10" # File download timeout (seconds) +os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1" # Disable symlinks warning +if load_config().get("disable_kokoro_internet", False): + print("INFO: Kokoro's internet access is disabled.") + os.environ["HF_HUB_OFFLINE"] = "1" # Disable Hugging Face Hub internet access + from abogen.gui import abogen -from abogen.utils import get_resource_path from abogen.constants import PROGRAM_NAME, VERSION # Set environment variables for AMD ROCm diff --git a/abogen/utils.py b/abogen/utils.py index 8c32c33..1a88a00 100644 --- a/abogen/utils.py +++ b/abogen/utils.py @@ -7,11 +7,8 @@ import subprocess import re from threading import Thread -# suppress warnings and disable HF hub symlink warnings -os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1" warnings.filterwarnings("ignore") - def get_resource_path(package, resource): """ Get the path to a resource file, with fallback to local file system.