diff --git a/bypy/sources.json b/bypy/sources.json index 3f74e1e48c..3ffe389537 100644 --- a/bypy/sources.json +++ b/bypy/sources.json @@ -1156,5 +1156,16 @@ "hash": "sha256:c3f9e322b1ebeebd44e3d9d2d9b124e0c550c1ef41bd552afdcdd719516ee41a", "urls": ["pypi"] } + }, + { + "name": "piper", + "os": "linux", + "unix": { + "filename": "piper-2023.11.14.tar.gz", + "hash": "sha256:8b684e102cfe23af097830db9555a8641f17735725853c531a1daeb34b6ed1a8", + "urls": ["https://github.com/rhasspy/piper/archive/refs/tags/2023.11.14-2.tar.gz"] + } } + + ] diff --git a/setup/unix-ci.py b/setup/unix-ci.py index b8fdfbabea..4140170190 100644 --- a/setup/unix-ci.py +++ b/setup/unix-ci.py @@ -168,6 +168,7 @@ username = api elif action == 'test': os.environ['CI'] = 'true' os.environ['OPENSSL_MODULES'] = os.path.join(SW, 'lib', 'ossl-modules') + os.environ['PIPER_TTS_DIR'] = os.path.join(SW, 'piper') if ismacos: os.environ['SSL_CERT_FILE'] = os.path.abspath( 'resources/mozilla-ca-certs.pem') diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 8a9a6f124e..f94c84e049 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -505,3 +505,18 @@ def bundled_binaries_dir() -> str: if (islinux or isbsd) and getattr(sys, 'frozen', False): return os.path.join(sys.executables_location, 'bin') return '' + + +@lru_cache(2) +def piper_cmdline() -> tuple[str, ...]: + ext = '.exe' if iswindows else '' + if bbd := bundled_binaries_dir(): + # TODO: Add path to espeak-ng-data with -- + return (os.path.join(bbd, 'piper' + ext),) + if pd := os.environ.get('PIPER_TTS_DIR'): + return (os.path.join(pd, 'piper' + ext),) + import shutil + exe = shutil.which('piper-tts') + if exe: + return (exe,) + return () diff --git a/src/calibre/gui2/tts/piper.py b/src/calibre/gui2/tts/piper.py index 2eaf73d2bf..21f5f12c3d 100644 --- a/src/calibre/gui2/tts/piper.py +++ b/src/calibre/gui2/tts/piper.py @@ -29,9 +29,9 @@ from qt.core import ( sip, ) -from calibre.constants import cache_dir, is_debugging +from calibre.constants import cache_dir, is_debugging, piper_cmdline from calibre.gui2 import error_dialog -from calibre.gui2.tts.types import EngineSpecificSettings, Quality, TTSBackend, Voice, piper_cmdline, widget_parent +from calibre.gui2.tts.types import EngineSpecificSettings, Quality, TTSBackend, Voice, widget_parent from calibre.spell.break_iterator import PARAGRAPH_SEPARATOR, split_into_sentences_for_tts from calibre.utils.localization import canonicalize_lang, get_lang from calibre.utils.resources import get_path as P diff --git a/src/calibre/gui2/tts/types.py b/src/calibre/gui2/tts/types.py index dc9918e6b7..34f3fa7729 100644 --- a/src/calibre/gui2/tts/types.py +++ b/src/calibre/gui2/tts/types.py @@ -9,7 +9,7 @@ from typing import Literal, NamedTuple from qt.core import QApplication, QLocale, QObject, QTextToSpeech, QVoice, QWidget, pyqtSignal -from calibre.constants import bundled_binaries_dir, islinux, ismacos, iswindows +from calibre.constants import islinux, ismacos, iswindows, piper_cmdline from calibre.utils.config import JSONConfig from calibre.utils.config_base import tweaks from calibre.utils.localization import canonicalize_lang @@ -21,20 +21,6 @@ def load_config() -> JSONConfig: return JSONConfig(CONFIG_NAME) -@lru_cache(2) -def piper_cmdline() -> tuple[str, ...]: - ext = '.exe' if iswindows else '' - if bbd := bundled_binaries_dir(): - # TODO: Add path to espeak-ng-data with -- - return (os.path.join(bbd, 'piper' + ext),) - import shutil - exe = shutil.which('piper-tts') - if exe: - return (exe,) - return () - - - class TrackingCapability(Enum): NoTracking: int = auto() WordByWord: int = auto() diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index 6cd53e0fe4..50c2066ab8 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -123,6 +123,15 @@ class BuildTest(unittest.TestCase): from speechd.client import SSIPClient del SSIPClient + @unittest.skipUnless(islinux, 'Piper only used on Linux') + def test_piper(self): + import subprocess + + from calibre.constants import piper_cmdline + self.assertTrue(piper_cmdline()) + raw = subprocess.check_output(piper_cmdline() + ('-h',), stderr=subprocess.STDOUT).decode() + self.assertIn('--sentence_silence', raw) + def test_zeroconf(self): import ifaddr import zeroconf as z