mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
Added "Replace single newlines with spaces" and small improvements
This commit is contained in:
@@ -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
|
||||||
@@ -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
@@ -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"
|
||||||
|
|||||||
@@ -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"):
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user