Added "Replace single newlines with spaces" and small improvements

This commit is contained in:
Deniz Şafak
2025-04-28 04:59:51 +03:00
parent a6bdc9c086
commit 4a7f1767b9
7 changed files with 35 additions and 11 deletions
+1
View File
@@ -1 +1,2 @@
- Added "Replace single newlines with spaces" option in the menu. This can be useful for texts that have imaginary line breaks (for example LICENSE files).
- Fixed "'utf-8' codec can't decode byte" error, mentioned in #3 by @nigelp - Fixed "'utf-8' codec can't decode byte" error, mentioned in #3 by @nigelp
+6 -1
View File
@@ -56,7 +56,7 @@ sudo dnf install espeak-ng
# Install abogen # Install abogen
pip install abogen pip install abogen
``` ```
> If you get "No matching distribution found" error, try installing it on supported Python (3.10 to 3.12). You can use [pyenv](https://github.com/pyenv/pyenv) to manage multiple Python versions easily in Linux. > If you get "No matching distribution found" error, try installing it on supported Python (3.10 to 3.12). You can use [pyenv](https://github.com/pyenv/pyenv) to manage multiple Python versions easily in Linux. Watch this [video](https://www.youtube.com/watch?v=MVyb-nI4KyI) by NetworkChuck for a quick guide.
Then simply run by typing: Then simply run by typing:
@@ -117,6 +117,11 @@ keep-open=yes
--audio-device=openal --audio-device=openal
--sub-margin-x=235 --sub-margin-x=235
--sub-pos=60 --sub-pos=60
# --- Audio Quality ---
audio-spdif=ac3,dts,eac3,truehd,dts-hd
audio-channels=auto
audio-samplerate=48000
volume-max=200
``` ```
## `Similar Projects` ## `Similar Projects`
+1 -1
View File
@@ -1,4 +1,4 @@
from utils import get_version, get_user_config_path from utils import get_version
# Program Information # Program Information
PROGRAM_NAME = "abogen" PROGRAM_NAME = "abogen"
+4
View File
@@ -170,6 +170,10 @@ class ConversionThread(QThread):
self.log_updated.emit(f"- Subtitle mode: {self.subtitle_mode}") self.log_updated.emit(f"- Subtitle mode: {self.subtitle_mode}")
self.log_updated.emit(f"- Output format: {self.output_format}") self.log_updated.emit(f"- Output format: {self.output_format}")
self.log_updated.emit(f"- Save option: {self.save_option}") self.log_updated.emit(f"- Save option: {self.save_option}")
if self.replace_single_newlines:
self.log_updated.emit(
f"- Replace single newlines: Yes"
)
# Display save_chapters_separately flag if it's set # Display save_chapters_separately flag if it's set
if hasattr(self, "save_chapters_separately"): if hasattr(self, "save_chapters_separately"):
+15
View File
@@ -467,6 +467,7 @@ class abogen(QWidget):
self.use_gpu = self.config.get( self.use_gpu = self.config.get(
"use_gpu", True "use_gpu", True
) # Load GPU setting with default True ) # Load GPU setting with default True
self.replace_single_newlines = self.config.get("replace_single_newlines", False)
self._pending_close_event = None self._pending_close_event = None
self.gpu_ok = False # Initialize GPU availability status self.gpu_ok = False # Initialize GPU availability status
@@ -1059,6 +1060,8 @@ class abogen(QWidget):
self.conversion_thread.file_size_str = file_size_str self.conversion_thread.file_size_str = file_size_str
# Pass max_subtitle_words from config # Pass max_subtitle_words from config
self.conversion_thread.max_subtitle_words = self.max_subtitle_words self.conversion_thread.max_subtitle_words = self.max_subtitle_words
# Pass replace_single_newlines setting
self.conversion_thread.replace_single_newlines = self.replace_single_newlines
# Pass chapter count for EPUB or PDF files # Pass chapter count for EPUB or PDF files
if self.selected_file_type in ["epub", "pdf"] and hasattr( if self.selected_file_type in ["epub", "pdf"] and hasattr(
self, "selected_chapters" self, "selected_chapters"
@@ -1499,6 +1502,13 @@ class abogen(QWidget):
"""Show a dropdown menu for settings options.""" """Show a dropdown menu for settings options."""
menu = QMenu(self) menu = QMenu(self)
# Add replace single newlines option
newline_action = QAction("Replace single newlines with spaces", self)
newline_action.setCheckable(True)
newline_action.setChecked(self.replace_single_newlines)
newline_action.triggered.connect(self.toggle_replace_single_newlines)
menu.addAction(newline_action)
# Add max words per subtitle option # Add max words per subtitle option
max_words_action = QAction("Configure max words per subtitle", self) max_words_action = QAction("Configure max words per subtitle", self)
max_words_action.triggered.connect(self.set_max_subtitle_words) max_words_action.triggered.connect(self.set_max_subtitle_words)
@@ -1545,6 +1555,11 @@ class abogen(QWidget):
menu.exec_(self.settings_btn.mapToGlobal(QPoint(0, self.settings_btn.height()))) menu.exec_(self.settings_btn.mapToGlobal(QPoint(0, self.settings_btn.height())))
def toggle_replace_single_newlines(self, checked):
self.replace_single_newlines = checked
self.config["replace_single_newlines"] = checked
save_config(self.config)
def reveal_config_in_explorer(self): def reveal_config_in_explorer(self):
"""Open the configuration file location in file explorer.""" """Open the configuration file location in file explorer."""
from utils import get_user_config_path from utils import get_user_config_path
+7 -3
View File
@@ -69,13 +69,17 @@ def get_user_config_path():
_sleep_procs = {"Darwin": None, "Linux": None} # Store sleep prevention processes _sleep_procs = {"Darwin": None, "Linux": None} # Store sleep prevention processes
def clean_text(text): def clean_text(text, *args, **kwargs):
# Load replace_single_newlines from config
cfg = load_config()
replace_single_newlines = cfg.get("replace_single_newlines", False)
# Trim spaces and tabs at the start and end of each line, preserving blank lines # Trim spaces and tabs at the start and end of each line, preserving blank lines
text = "\n".join(line.strip() for line in text.splitlines()) text = "\n".join(line.strip() for line in text.splitlines())
# Standardize paragraph breaks (multiple newlines become exactly two) and trim overall whitespace # Standardize paragraph breaks (multiple newlines become exactly two) and trim overall whitespace
text = re.sub(r"\n{3,}", "\n\n", text).strip() text = re.sub(r"\n{3,}", "\n\n", text).strip()
# Replace single newlines with spaces, but preserve double newlines # Optionally replace single newlines with spaces, but preserve double newlines
# text = re.sub(r"(?<!\n)\n(?!\n)", " ", text) if replace_single_newlines:
text = re.sub(r"(?<!\n)\n(?!\n)", " ", text)
# Collapse multiple spaces and tabs into a single space # Collapse multiple spaces and tabs into a single space
text = re.sub(r"[ \t]+", " ", text) text = re.sub(r"[ \t]+", " ", text)
return text return text
-5
View File
@@ -40,11 +40,6 @@ Run this FFmpeg command to create the tiny video:
ffmpeg -loop 1 -framerate 24 -i bg.jpg -i audio.wav -vf "ass=your_subtitle_demo.ass" -c:v libvpx-vp9 -b:v 0 -crf 30 -c:a libopus -shortest demo.webm ffmpeg -loop 1 -framerate 24 -i bg.jpg -i audio.wav -vf "ass=your_subtitle_demo.ass" -c:v libvpx-vp9 -b:v 0 -crf 30 -c:a libopus -shortest demo.webm
``` ```
That's it! The magic happens because:
- We use a single static background image instead of many frames
- The subtitles are stored as text (vector data), not as pixels
- VP9 video codec with Opus audio provides excellent compression
## For Higher Quality (But Larger) Video (.mp4) ## For Higher Quality (But Larger) Video (.mp4)
If you need better quality for distribution, use this command instead: If you need better quality for distribution, use this command instead: