52 lines
No EOL
1.8 KiB
Python
52 lines
No EOL
1.8 KiB
Python
# tts_utils.py
|
|
import re
|
|
from bs4 import BeautifulSoup
|
|
|
|
|
|
def get_configured_tts_rate(settings: dict) -> str:
|
|
"""Extracts speed multiplier from settings dict and converts to Edge TTS percentage string (e.g., '-25%')."""
|
|
# Query the exact key name shown in SQLite database: 'tts_playback_speed'
|
|
raw_val = settings.get("tts_playback_speed", 1.0) if settings else 1.0
|
|
|
|
try:
|
|
raw_rate = float(raw_val)
|
|
except (TypeError, ValueError):
|
|
raw_rate = 1.0
|
|
|
|
# Calculate percentage shift relative to baseline 1.0 (e.g., 0.75 -> -25%)
|
|
pct = int(round((raw_rate - 1.0) * 100))
|
|
rate_str = f"+{pct}%" if pct >= 0 else f"{pct}%"
|
|
|
|
print(
|
|
f"[TTS Debug] DB Key 'tts_playback_speed': {raw_val} -> Formatted Rate: {rate_str}"
|
|
)
|
|
return rate_str
|
|
|
|
|
|
def parse_text_for_edgetts(html_content: str) -> str:
|
|
"""Strips content between <meta sound-off> and <meta sound-on> tags,
|
|
handling optional whitespace inside the tag brackets (e.g., <meta sound-off >).
|
|
Converts remaining HTML tags to clean spoken text.
|
|
"""
|
|
if not html_content:
|
|
return ""
|
|
|
|
# Flexible regex to slice out everything from <meta sound-off ...> through <meta sound-on ...>
|
|
pattern = re.compile(
|
|
r"<meta\s+sound-off\s*\/?>.*?<meta\s+sound-on\s*\/?>",
|
|
re.DOTALL | re.IGNORECASE,
|
|
)
|
|
cleaned_html = re.sub(pattern, "", html_content)
|
|
|
|
# Handle unclosed <meta sound-off> (mute rest of string from that point)
|
|
if re.search(r"<meta\s+sound-off\s*\/?>", cleaned_html, re.IGNORECASE):
|
|
cleaned_html = re.split(
|
|
r"<meta\s+sound-off\s*\/?>", cleaned_html, flags=re.IGNORECASE
|
|
)[0]
|
|
|
|
# Convert remaining HTML into plain text for speech
|
|
soup = BeautifulSoup(cleaned_html, "html.parser")
|
|
text = soup.get_text(separator=" ")
|
|
|
|
# Normalize extra whitespace
|
|
return re.sub(r"\s+", " ", text).strip() |