Anki/qt/aqt/tts.py

67 lines
1.9 KiB
Python

"""
todo
"""
import subprocess
import time
from concurrent.futures import Future
from typing import cast
from anki.sound import AVTag, TTSTag
from aqt.sound import OnDoneCallback, Player, PlayerInterrupted
from aqt.taskman import TaskManager
class TTSPlayer(Player): # pylint: disable=abstract-method
def can_play(self, tag: AVTag) -> bool:
return isinstance(tag, TTSTag)
class MacTTSPlayer(TTSPlayer):
def __init__(self, taskman: TaskManager):
self._taskman = taskman
self._terminate_flag = False
def play(self, tag: AVTag, on_done: OnDoneCallback) -> None:
ttag = cast(TTSTag, tag)
self._taskman.run(
lambda: self._play(ttag), lambda ret: self._on_done(ret, on_done)
)
def _play(self, tag: TTSTag) -> None:
process = subprocess.Popen(
["say", "-v", "Alex", "-f", "-"],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
# write the input text to stdin
process.stdin.write(tag.text.encode("utf8"))
process.stdin.close()
# and wait for termination
while True:
try:
process.wait(0.1)
if process.returncode != 0:
print(f"player got return code: {process.returncode}")
return
except subprocess.TimeoutExpired:
pass
if self._terminate_flag:
process.terminate()
self._terminate_flag = False
raise PlayerInterrupted()
def _on_done(self, ret: Future, cb: OnDoneCallback) -> None:
try:
ret.result()
except PlayerInterrupted:
# don't fire done callback when interrupted
return
cb()
def stop(self):
self._terminate_flag = True
# block until stopped
while self._terminate_flag:
time.sleep(0.1)