aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Lüftinger <22958522+LokiLuciferase@users.noreply.github.com>2023-06-11 07:06:40 +0200
committerGitHub <noreply@github.com>2023-06-11 12:06:40 +0700
commit1b4a0e46163804251fc2c0605ae713a438792cc4 (patch)
tree102b4fdb7ebf8ee4eff77959eb288e90c19032d7
parentc7c0de3eeff10cd4476b58986b212988e791ae69 (diff)
downloadepy-1b4a0e46163804251fc2c0605ae713a438792cc4.tar.gz
add speaker support for gtts-cli | mpv (#88)
-rw-r--r--README.md1
-rw-r--r--src/epy_reader/speakers/__init__.py2
-rw-r--r--src/epy_reader/speakers/gtts_mpv.py39
-rw-r--r--src/epy_reader/utils.py4
4 files changed, 44 insertions, 2 deletions
diff --git a/README.md b/README.md
index f8228ae..b2dc4ba 100644
--- a/README.md
+++ b/README.md
@@ -140,6 +140,7 @@ List of supported engines:
- `mimic`
- `pico2wave`
+- `gtts-mpv` (requires both [gTTS](https://pypi.org/project/gTTS) and [MPV](https://www.mpv.io))
## Dictionary
diff --git a/src/epy_reader/speakers/__init__.py b/src/epy_reader/speakers/__init__.py
index 078be31..4628714 100644
--- a/src/epy_reader/speakers/__init__.py
+++ b/src/epy_reader/speakers/__init__.py
@@ -2,8 +2,10 @@ __all__ = [
"SpeakerBaseModel",
"SpeakerMimic",
"SpeakerPico",
+ "SpeakerGttsMPV"
]
from epy_reader.speakers.base import SpeakerBaseModel
from epy_reader.speakers.mimic import SpeakerMimic
from epy_reader.speakers.pico import SpeakerPico
+from epy_reader.speakers.gtts_mpv import SpeakerGttsMPV
diff --git a/src/epy_reader/speakers/gtts_mpv.py b/src/epy_reader/speakers/gtts_mpv.py
new file mode 100644
index 0000000..a4406dd
--- /dev/null
+++ b/src/epy_reader/speakers/gtts_mpv.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+
+import shutil
+import subprocess
+
+from epy_reader.speakers.base import SpeakerBaseModel
+
+
+class SpeakerGttsMPV(SpeakerBaseModel):
+ cmd = "gtts-mpv"
+ available = bool(shutil.which("gtts-cli") and shutil.which("mpv"))
+
+ def speak(self, text: str) -> None:
+ self._gtts_process = subprocess.Popen(
+ ["gtts-cli", "-", *self.args],
+ text=True,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ self._mpv_process = subprocess.Popen(
+ ["mpv", "-"],
+ stdin=self._gtts_process.stdout,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ assert self._gtts_process.stdin
+ self._gtts_process.stdin.write(text)
+ self._gtts_process.stdin.close()
+
+ def is_done(self) -> bool:
+ return self._mpv_process.poll() is not None
+
+ def stop(self) -> None:
+ self._gtts_process.terminate()
+ self._mpv_process.terminate()
+
+ def cleanup(self) -> None:
+ pass
diff --git a/src/epy_reader/utils.py b/src/epy_reader/utils.py
index 5bba7f6..bb24106 100644
--- a/src/epy_reader/utils.py
+++ b/src/epy_reader/utils.py
@@ -10,7 +10,7 @@ from epy_reader.ebooks import URL, Azw, Ebook, Epub, FictionBook, Mobi
from epy_reader.lib import is_url, tuple_subtract
from epy_reader.models import Key, LettersCount, NoUpdate, ReadingState, TextStructure, TocEntry
from epy_reader.parser import parse_html
-from epy_reader.speakers import SpeakerBaseModel, SpeakerMimic, SpeakerPico
+from epy_reader.speakers import SpeakerBaseModel, SpeakerMimic, SpeakerPico, SpeakerGttsMPV
def get_ebook_obj(filepath: str) -> Ebook:
@@ -367,7 +367,7 @@ def count_letters_parallel(ebook: Ebook, child_conn) -> None:
def construct_speaker(
preferred: Optional[str] = None, args: List[str] = []
) -> Optional[SpeakerBaseModel]:
- available_speakers = [SpeakerMimic, SpeakerPico]
+ available_speakers = [SpeakerMimic, SpeakerPico, SpeakerGttsMPV]
sorted_speakers = (
sorted(available_speakers, key=lambda x: int(x.cmd == preferred), reverse=True)
if preferred