mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 21:50:28 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7631cc852 | ||
|
|
6f09efd018 | ||
|
|
f1903eb6ac | ||
|
|
977b2a736c | ||
|
|
1f51e3edd3 |
@@ -1,3 +1,10 @@
|
||||
# 1.1.5
|
||||
- Changed the temporary directory path to user's cache directory, which is more appropriate for storing cache files and avoids issues with unintended cleanup.
|
||||
- Fixed the isssue where extra metadata information was not being saved to M4B files when they have no chapters, ensuring that all metadata is correctly written to the output file.
|
||||
- Fixed sleep prevention process not ending if program exited using Ctrl+C or kill.
|
||||
- Improved automatic filename suffixing to better prevent overwriting files with the same name, even if they have different extensions.
|
||||
- Improvements in code and documentation.
|
||||
|
||||
# 1.1.4
|
||||
- Fixed extra metadata information not being saved to M4B files, ensuring that all metadata is correctly written to the output file.
|
||||
- Reformatted the code using Black for better readability and consistency.
|
||||
|
||||
@@ -149,9 +149,9 @@ Here’s Abogen in action: in this demo, it processes ∼3,000 characters of tex
|
||||
| **Configure max lines in log window** | Configures the maximum number of lines to display in the log window. |
|
||||
| **Separate chapters audio format** | Configures the audio format for separate chapters as `wav`, `flac`, `mp3`, or `opus`. |
|
||||
| **Create desktop shortcut** | Creates a shortcut on your desktop for easy access. |
|
||||
| **Open config.json directory** | Opens the directory where the configuration file is stored. |
|
||||
| **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. |
|
||||
| **Open config directory** | Opens the directory where the configuration file is stored. |
|
||||
| **Open cache directory** | Opens the cache directory where converted text files are stored. |
|
||||
| **Clear cache files** | Deletes cache 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. |
|
||||
@@ -174,7 +174,7 @@ Abogen will process each item in the queue automatically, saving outputs as conf
|
||||
> Special thanks to [@jborza](https://github.com/jborza) for adding queue mode in PR [#35](https://github.com/denizsafak/abogen/pull/35)
|
||||
|
||||
## `About Chapter Markers`
|
||||
When you process ePUB or PDF files, Abogen converts them into text files stored in your temporary directory. When you click "Edit," you're actually modifying these converted text files. In these text files, you'll notice tags that look like this:
|
||||
When you process ePUB or PDF files, Abogen converts them into text files stored in your cache directory. When you click "Edit," you're actually modifying these converted text files. In these text files, you'll notice tags that look like this:
|
||||
|
||||
```
|
||||
<<CHAPTER_MARKER:Chapter Title>>
|
||||
@@ -270,7 +270,7 @@ Abogen launches automatically inside the container.
|
||||
|
||||
Known issues:
|
||||
- Audio preview is not working inside container (ALSA error).
|
||||
- `Open temp directory` and `Open configuration directory` options in settings not working. (Tried pcmanfm, did not work with Abogen).
|
||||
- `Open cache directory` and `Open configuration directory` options in settings not working. (Tried pcmanfm, did not work with Abogen).
|
||||
|
||||
(Special thanks to [@geo38](https://www.reddit.com/user/geo38/) from Reddit, who provided the Dockerfile and instructions in [this comment](https://www.reddit.com/r/selfhosted/comments/1k8x1yo/comment/mpe0bz8/).)
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.1.4
|
||||
1.1.5
|
||||
@@ -31,6 +31,28 @@ LANGUAGE_DESCRIPTIONS = {
|
||||
"z": "Mandarin Chinese",
|
||||
}
|
||||
|
||||
# Supported sound formats
|
||||
SUPPORTED_SOUND_FORMATS = [
|
||||
"wav",
|
||||
"mp3",
|
||||
"opus",
|
||||
"m4b",
|
||||
"flac",
|
||||
]
|
||||
|
||||
# Supported subtitle formats
|
||||
SUPPORTED_SUBTITLE_FORMATS = [
|
||||
"srt",
|
||||
"ass",
|
||||
]
|
||||
|
||||
# Supported input formats
|
||||
SUPPORTED_INPUT_FORMATS = [
|
||||
"epub",
|
||||
"pdf",
|
||||
"txt",
|
||||
]
|
||||
|
||||
# Supported languages for subtitle generation
|
||||
# Currently, only 'a (American English)' and 'b (British English)' are supported for subtitle generation.
|
||||
# This is because tokens that contain timestamps are not generated for other languages in the Kokoro pipeline.
|
||||
|
||||
+15
-24
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import time
|
||||
import chardet
|
||||
import charset_normalizer
|
||||
@@ -9,14 +8,15 @@ from platformdirs import user_desktop_dir
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QTimer
|
||||
from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QDialog, QLabel, QDialogButtonBox
|
||||
import soundfile as sf
|
||||
from abogen.utils import clean_text, create_process
|
||||
from abogen.utils import clean_text, create_process, get_user_cache_path
|
||||
from abogen.constants import (
|
||||
PROGRAM_NAME,
|
||||
LANGUAGE_DESCRIPTIONS,
|
||||
SAMPLE_VOICE_TEXTS,
|
||||
COLORS,
|
||||
CHAPTER_OPTIONS_COUNTDOWN,
|
||||
SUBTITLE_FORMATS,
|
||||
SUPPORTED_SOUND_FORMATS,
|
||||
SUPPORTED_SUBTITLE_FORMATS,
|
||||
)
|
||||
from abogen.voice_formulas import get_new_voice
|
||||
import abogen.hf_tracker as hf_tracker
|
||||
@@ -426,29 +426,19 @@ class ConversionThread(QThread):
|
||||
)
|
||||
# Find a unique suffix for both folder and merged file, always
|
||||
counter = 1
|
||||
allowed_exts = set(SUPPORTED_SOUND_FORMATS + SUPPORTED_SUBTITLE_FORMATS)
|
||||
while True:
|
||||
suffix = f"_{counter}" if counter > 1 else ""
|
||||
chapters_out_dir_candidate = os.path.join(
|
||||
parent_dir, f"{base_name}{suffix}_chapters"
|
||||
)
|
||||
merged_file_candidate = os.path.join(
|
||||
parent_dir, f"{base_name}{suffix}.{self.output_format}"
|
||||
# Only check for files with allowed extensions (extension without dot, case-insensitive)
|
||||
clash = any(
|
||||
os.path.splitext(fname)[0] == f"{base_name}{suffix}" and
|
||||
os.path.splitext(fname)[1][1:].lower() in allowed_exts
|
||||
for fname in os.listdir(parent_dir)
|
||||
)
|
||||
merged_srt_candidate = (
|
||||
os.path.splitext(merged_file_candidate)[0] + ".srt"
|
||||
)
|
||||
if (
|
||||
not os.path.exists(chapters_out_dir_candidate)
|
||||
and (
|
||||
not merge_chapters_at_end
|
||||
or not os.path.exists(merged_file_candidate)
|
||||
)
|
||||
and (
|
||||
self.subtitle_mode == "Disabled"
|
||||
or not merge_chapters_at_end
|
||||
or not os.path.exists(merged_srt_candidate)
|
||||
)
|
||||
):
|
||||
if not os.path.exists(chapters_out_dir_candidate) and not clash:
|
||||
break
|
||||
counter += 1
|
||||
if save_chapters_separately and total_chapters > 1:
|
||||
@@ -492,6 +482,9 @@ class ConversionThread(QThread):
|
||||
static_ffmpeg.add_paths()
|
||||
merged_out_file = None
|
||||
ffmpeg_proc = None
|
||||
metadata_options = (
|
||||
self._extract_and_add_metadata_tags_to_ffmpeg_cmd()
|
||||
)
|
||||
# Prepare ffmpeg command for m4b output
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
@@ -513,6 +506,7 @@ class ConversionThread(QThread):
|
||||
"-movflags",
|
||||
"+faststart+use_metadata_tags",
|
||||
]
|
||||
cmd += metadata_options
|
||||
cmd.append(merged_out_path)
|
||||
ffmpeg_proc = create_process(cmd, stdin=subprocess.PIPE, text=False)
|
||||
elif self.output_format == "opus":
|
||||
@@ -1293,10 +1287,7 @@ class VoicePreviewThread(QThread):
|
||||
self.use_gpu = use_gpu
|
||||
|
||||
# Cache location for preview audio
|
||||
self.cache_dir = os.path.join(
|
||||
tempfile.gettempdir(), PROGRAM_NAME, "preview_cache"
|
||||
)
|
||||
os.makedirs(self.cache_dir, exist_ok=True)
|
||||
self.cache_dir = get_user_cache_path("preview_cache")
|
||||
|
||||
# Calculate cache path
|
||||
self.cache_path = self._get_cache_path()
|
||||
|
||||
+58
-59
@@ -62,6 +62,7 @@ from abogen.utils import (
|
||||
prevent_sleep_end,
|
||||
calculate_text_length,
|
||||
get_resource_path,
|
||||
get_user_cache_path,
|
||||
LoadPipelineThread,
|
||||
)
|
||||
from abogen.conversion import ConversionThread, VoicePreviewThread, PlayAudioThread
|
||||
@@ -564,12 +565,12 @@ class TextboxDialog(QDialog):
|
||||
self.reject()
|
||||
else:
|
||||
# Check if we need to warn about overwriting a non-temporary file
|
||||
if hasattr(self, "is_non_temp_file") and self.is_non_temp_file:
|
||||
if hasattr(self, "is_non_cache_file") and self.is_non_cache_file:
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setIcon(QMessageBox.Warning)
|
||||
msg_box.setWindowTitle("File Overwrite Warning")
|
||||
msg_box.setText(
|
||||
f"You are about to overwrite the original file:\n{self.non_temp_file_path}"
|
||||
f"You are about to overwrite the original file:\n{self.non_cache_file_path}"
|
||||
)
|
||||
msg_box.setInformativeText("Do you want to continue?")
|
||||
msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||
@@ -591,11 +592,11 @@ class TextboxDialog(QDialog):
|
||||
|
||||
# Get default filename from original file if editing
|
||||
initial_path = ""
|
||||
if hasattr(self, "non_temp_file_path") and self.non_temp_file_path:
|
||||
initial_path = self.non_temp_file_path
|
||||
if hasattr(self, "non_cache_file_path") and self.non_cache_file_path:
|
||||
initial_path = self.non_cache_file_path
|
||||
|
||||
# For EPUB and PDF files, use the displayed_file_path from the main window
|
||||
# This gives a better filename instead of the temporary file path
|
||||
# This gives a better filename instead of the cache file path
|
||||
main_window = self.parent()
|
||||
if (
|
||||
hasattr(main_window, "displayed_file_path")
|
||||
@@ -1195,7 +1196,7 @@ class abogen(QWidget):
|
||||
if book_path.lower().endswith(".pdf"):
|
||||
self.pdf_has_bookmarks = getattr(dialog, "has_pdf_bookmarks", False)
|
||||
|
||||
# Use "abogen" prefix for temporary files
|
||||
# Use "abogen" prefix for cache files
|
||||
# Extract base name without extension
|
||||
base_name = os.path.splitext(os.path.basename(book_path))[0]
|
||||
|
||||
@@ -1205,15 +1206,15 @@ class abogen(QWidget):
|
||||
self, "Select Project Folder", "", QFileDialog.ShowDirsOnly
|
||||
)
|
||||
if not project_dir:
|
||||
# User cancelled, fallback to temp
|
||||
# User cancelled, fallback to cache
|
||||
self.save_as_project = False
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME)
|
||||
cache_dir = get_user_cache_path()
|
||||
else:
|
||||
# Create project folder structure
|
||||
project_name = f"{base_name}_project"
|
||||
project_dir = os.path.join(project_dir, project_name)
|
||||
temp_dir = os.path.join(project_dir, "text")
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
cache_dir = os.path.join(project_dir, "text")
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
|
||||
# Save metadata if available
|
||||
meta_dir = os.path.join(project_dir, "metadata")
|
||||
@@ -1268,11 +1269,10 @@ class abogen(QWidget):
|
||||
with open(cover_path, "wb") as f:
|
||||
f.write(dialog.book_metadata["cover_image"])
|
||||
else:
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME)
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
cache_dir = get_user_cache_path()
|
||||
|
||||
fd, tmp = tempfile.mkstemp(
|
||||
prefix=f"{base_name}_", suffix=".txt", dir=temp_dir
|
||||
prefix=f"{base_name}_", suffix=".txt", dir=cache_dir
|
||||
)
|
||||
os.close(fd)
|
||||
with open(tmp, "w", encoding="utf-8") as f:
|
||||
@@ -1293,13 +1293,13 @@ class abogen(QWidget):
|
||||
return
|
||||
|
||||
editing = False
|
||||
is_temp_file = False
|
||||
is_cache_file = False
|
||||
# If path is explicitly provided, use it
|
||||
if file_path and os.path.exists(file_path):
|
||||
editing = True
|
||||
edit_file = file_path
|
||||
# Check if this is a temporary file
|
||||
is_temp_file = tempfile.gettempdir() in file_path
|
||||
# Check if this is a cache file
|
||||
is_cache_file = get_user_cache_path() in file_path
|
||||
# Otherwise use selected_file if it's a txt file
|
||||
elif (
|
||||
self.selected_file_type == "txt"
|
||||
@@ -1308,8 +1308,8 @@ class abogen(QWidget):
|
||||
):
|
||||
editing = True
|
||||
edit_file = self.selected_file
|
||||
# Check if this is a temporary file
|
||||
is_temp_file = tempfile.gettempdir() in self.selected_file
|
||||
# Check if this is a cache file
|
||||
is_cache_file = get_user_cache_path() in self.selected_file
|
||||
|
||||
dialog = TextboxDialog(self)
|
||||
if editing:
|
||||
@@ -1321,10 +1321,10 @@ class abogen(QWidget):
|
||||
dialog.text_edit.toPlainText()
|
||||
) # Store original text
|
||||
|
||||
# If editing a non-temporary file, alert the user
|
||||
if not is_temp_file:
|
||||
dialog.is_non_temp_file = True
|
||||
dialog.non_temp_file_path = edit_file
|
||||
# If editing a non-cache file, alert the user
|
||||
if not is_cache_file:
|
||||
dialog.is_non_cache_file = True
|
||||
dialog.non_cache_file_path = edit_file
|
||||
except Exception:
|
||||
pass
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
@@ -1342,10 +1342,9 @@ class abogen(QWidget):
|
||||
# Hide chapters button since we're using custom text now
|
||||
self.input_box.chapters_btn.hide()
|
||||
else:
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME)
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
cache_dir = get_user_cache_path()
|
||||
fd, tmp = tempfile.mkstemp(
|
||||
prefix="abogen_", suffix=".txt", dir=temp_dir
|
||||
prefix="abogen_", suffix=".txt", dir=cache_dir
|
||||
)
|
||||
os.close(fd)
|
||||
with open(tmp, "w", encoding="utf-8") as f:
|
||||
@@ -2153,7 +2152,7 @@ class abogen(QWidget):
|
||||
if not lang_to_cache or not voice_to_cache: # Not enough info
|
||||
return None
|
||||
|
||||
cache_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME, "preview_cache")
|
||||
cache_dir = get_user_cache_path("preview_cache")
|
||||
|
||||
if "*" in voice_to_cache: # Voice formula
|
||||
voice_id = (
|
||||
@@ -2771,17 +2770,17 @@ class abogen(QWidget):
|
||||
reveal_config_action.triggered.connect(self.reveal_config_in_explorer)
|
||||
menu.addAction(reveal_config_action)
|
||||
|
||||
# Add open temp directory option
|
||||
open_temp_action = QAction("Open temp directory", self)
|
||||
open_temp_action.triggered.connect(self.open_temp_directory)
|
||||
menu.addAction(open_temp_action)
|
||||
# Add open cache directory option
|
||||
open_cache_action = QAction("Open cache directory", self)
|
||||
open_cache_action.triggered.connect(self.open_cache_directory)
|
||||
menu.addAction(open_cache_action)
|
||||
|
||||
# Add clear temporary files option
|
||||
clear_temp_action = QAction("Clear temporary files", self)
|
||||
clear_temp_action.triggered.connect(self.clear_temp_files)
|
||||
menu.addAction(clear_temp_action)
|
||||
# Add clear cache files option
|
||||
clear_cache_action = QAction("Clear cache files", self)
|
||||
clear_cache_action.triggered.connect(self.clear_cache_files)
|
||||
menu.addAction(clear_cache_action)
|
||||
|
||||
# Add seperator"
|
||||
# Add separator
|
||||
menu.addSeparator()
|
||||
|
||||
# Add "Disable Kokoro's internet access" option
|
||||
@@ -2900,21 +2899,21 @@ class abogen(QWidget):
|
||||
self, "Config Error", f"Could not open config location:\n{e}"
|
||||
)
|
||||
|
||||
def open_temp_directory(self):
|
||||
"""Open the temporary directory used by the program."""
|
||||
def open_cache_directory(self):
|
||||
"""Open the cache directory used by the program."""
|
||||
try:
|
||||
# Get the temp directory path
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME)
|
||||
# Get the cache directory path
|
||||
cache_dir = get_user_cache_path()
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
if not os.path.exists(temp_dir):
|
||||
os.makedirs(temp_dir)
|
||||
if not os.path.exists(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
|
||||
# Open the directory in file explorer
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(temp_dir))
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(cache_dir))
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self, "Temp Directory Error", f"Could not open temp directory:\n{e}"
|
||||
self, "Cache Directory Error", f"Could not open cache directory:\n{e}"
|
||||
)
|
||||
|
||||
def add_shortcut_to_desktop(self):
|
||||
@@ -3254,23 +3253,23 @@ Categories=AudioVideo;Audio;Utility;
|
||||
)
|
||||
pass
|
||||
|
||||
def clear_temp_files(self):
|
||||
"""Clear temporary files created by the program."""
|
||||
def clear_cache_files(self):
|
||||
"""Clear cache files created by the program."""
|
||||
import glob
|
||||
|
||||
try:
|
||||
# Get the abogen temp directory
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), PROGRAM_NAME)
|
||||
# Get the abogen cache directory
|
||||
cache_dir = get_user_cache_path()
|
||||
|
||||
# Find all .txt files in the abogen temp directory
|
||||
pattern = os.path.join(temp_dir, "*.txt")
|
||||
temp_files = glob.glob(pattern)
|
||||
# Find all .txt files in the abogen cache directory
|
||||
pattern = os.path.join(cache_dir, "*.txt")
|
||||
cache_files = glob.glob(pattern)
|
||||
|
||||
# Count the files
|
||||
file_count = len(temp_files)
|
||||
file_count = len(cache_files)
|
||||
|
||||
# Check for preview cache files
|
||||
preview_cache_dir = os.path.join(temp_dir, "preview_cache")
|
||||
preview_cache_dir = os.path.join(cache_dir, "preview_cache")
|
||||
preview_files = []
|
||||
if os.path.exists(preview_cache_dir):
|
||||
preview_pattern = os.path.join(preview_cache_dir, "*.wav")
|
||||
@@ -3280,16 +3279,16 @@ Categories=AudioVideo;Audio;Utility;
|
||||
|
||||
if file_count == 0 and preview_count == 0:
|
||||
QMessageBox.information(
|
||||
self, "No Temporary Files", "No temporary files were found."
|
||||
self, "No Cache Files", "No cache files were found."
|
||||
)
|
||||
return
|
||||
|
||||
# Create a custom message box with checkbox
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setIcon(QMessageBox.Question)
|
||||
msg_box.setWindowTitle("Clear Temporary Files")
|
||||
msg_box.setWindowTitle("Clear Cache Files")
|
||||
|
||||
msg_text = f"Found {file_count} temporary file{'s' if file_count != 1 else ''} in the {PROGRAM_NAME} temp folder."
|
||||
msg_text = f"Found {file_count} cache file{'s' if file_count != 1 else ''} in the {PROGRAM_NAME} cache folder."
|
||||
if preview_count > 0:
|
||||
msg_text += f"\nAlso found {preview_count} preview cache file{'s' if preview_count != 1 else ''}."
|
||||
|
||||
@@ -3313,7 +3312,7 @@ Categories=AudioVideo;Audio;Utility;
|
||||
|
||||
# Delete the text files
|
||||
deleted_count = 0
|
||||
for file_path in temp_files:
|
||||
for file_path in cache_files:
|
||||
try:
|
||||
os.remove(file_path)
|
||||
deleted_count += 1
|
||||
@@ -3336,12 +3335,12 @@ Categories=AudioVideo;Audio;Utility;
|
||||
result_msg += f"\nAlso deleted {deleted_preview_count} preview cache file{'s' if deleted_preview_count != 1 else ''}."
|
||||
|
||||
# Show results
|
||||
QMessageBox.information(self, "Temporary Files Cleared", result_msg)
|
||||
QMessageBox.information(self, "Cache Files Cleared", result_msg)
|
||||
|
||||
# If currently selected file is in the temp directory, clear the UI
|
||||
# If currently selected file is in the cache directory, clear the UI
|
||||
if (
|
||||
self.selected_file
|
||||
and os.path.dirname(self.selected_file) == temp_dir
|
||||
and os.path.dirname(self.selected_file) == cache_dir
|
||||
and self.selected_file.endswith(".txt")
|
||||
):
|
||||
self.input_box.clear_input()
|
||||
|
||||
+9
-1
@@ -3,6 +3,7 @@ import os
|
||||
import sys
|
||||
import platform
|
||||
import atexit
|
||||
import signal
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import qInstallMessageHandler, QtMsgType
|
||||
@@ -31,6 +32,14 @@ os.environ["MIOPEN_CONV_PRECISE_ROCM_TUNING"] = "0"
|
||||
# Reset sleep states
|
||||
atexit.register(prevent_sleep_end)
|
||||
|
||||
# Also handle signals (Ctrl+C, kill, etc.)
|
||||
def _cleanup_sleep(signum, frame):
|
||||
prevent_sleep_end()
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, _cleanup_sleep)
|
||||
signal.signal(signal.SIGTERM, _cleanup_sleep)
|
||||
|
||||
# Ensure sys.stdout and sys.stderr are valid in GUI mode
|
||||
if sys.stdout is None:
|
||||
sys.stdout = open(os.devnull, "w")
|
||||
@@ -41,7 +50,6 @@ if sys.stderr is None:
|
||||
if platform.system() == "Darwin" and platform.processor() == "arm":
|
||||
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
|
||||
|
||||
|
||||
# Custom message handler to filter out specific Qt warnings
|
||||
def qt_message_handler(mode, context, message):
|
||||
if "Wayland does not support QWindow::requestActivate()" in message:
|
||||
|
||||
+12
-3
@@ -74,14 +74,23 @@ def get_user_config_path():
|
||||
if os.path.exists(custom_dir):
|
||||
config_dir = custom_dir
|
||||
else:
|
||||
config_dir = user_config_dir("abogen", appauthor=False, roaming=True)
|
||||
config_dir = user_config_dir("abogen", appauthor=False, roaming=True, ensure_exists=True)
|
||||
else:
|
||||
# Windows and fallback case
|
||||
config_dir = user_config_dir("abogen", appauthor=False, roaming=True)
|
||||
config_dir = user_config_dir("abogen", appauthor=False, roaming=True, ensure_exists=True)
|
||||
|
||||
os.makedirs(config_dir, exist_ok=True)
|
||||
return os.path.join(config_dir, "config.json")
|
||||
|
||||
# Define cache path
|
||||
def get_user_cache_path(folder=None):
|
||||
from platformdirs import user_cache_dir
|
||||
|
||||
cache_dir = user_cache_dir("abogen", appauthor=False, opinion=True, ensure_exists=True)
|
||||
if folder:
|
||||
cache_dir = os.path.join(cache_dir, folder)
|
||||
# Ensure the directory exists
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
return cache_dir
|
||||
|
||||
_sleep_procs = {"Darwin": None, "Linux": None} # Store sleep prevention processes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user