Fixed speech-dispatcher library in Play Palace.

This commit is contained in:
Storm Dragon
2026-02-22 06:30:55 -05:00
parent 1f7858e1fa
commit c86edee113
4 changed files with 46 additions and 48 deletions
@@ -71,6 +71,7 @@ python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
- Mismatched `.install/<Game>.sh` vs `.launch/<Game>.game` names create orphaned or invisible entries. - Mismatched `.install/<Game>.sh` vs `.launch/<Game>.game` names create orphaned or invisible entries.
- Missing `installPath` reference in launcher prevents full uninstall. - Missing `installPath` reference in launcher prevents full uninstall.
- `game_removal` parses the first `installPath` match in launcher text, so comments containing `installPath` can break removal path detection.
- Missing `run_update()` in `.update` scripts breaks update flow. - Missing `run_update()` in `.update` scripts breaks update flow.
- Bypassing shared download helpers risks cache and validation regressions. - Bypassing shared download helpers risks cache and validation regressions.
- For `uv`-based Python games that use `accessible-output2`, include a host copy of `libspeechd.so.2` and export `LD_LIBRARY_PATH` from the launcher to avoid distro packaging differences. - For `uv`-based Python games that need `speechd`, copy host Python `speechd` bindings into a game-local directory and export `PYTHONPATH` from the launcher.
@@ -108,27 +108,24 @@ python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
- For edited bash scripts, run shellcheck and fix all errors. - For edited bash scripts, run shellcheck and fix all errors.
- If `shellcheck` is not installed, prompt the user to install it first (see `references/tooling-prereqs.md`). - If `shellcheck` is not installed, prompt the user to install it first (see `references/tooling-prereqs.md`).
## Pattern: uv + Speech Dispatcher Host Libraries ## Pattern: uv + Host Python speechd Bindings
Use this pattern for Python games installed with `uv` when runtime speech support depends on system `libspeechd`. Use this pattern for Python games installed with `uv` when runtime speech support depends on `import speechd`.
1. In installer script: 1. In installer script:
- Check dependencies: `git` and `uv`. - Check dependencies: `git`, `uv`, and host python binding import (`python-speechd:speechd`).
- Clone game repository into `${installPath}/<GameRepoDir>`. - Clone game repository into `${installPath}/<GameRepoDir>`.
- Run `uv sync` in the project directory that contains `pyproject.toml`. - Run `uv sync` in the project directory that contains `pyproject.toml`.
- Locate `libspeechd.so.2` from host system using: - Resolve speechd source path from host Python via:
- `ldconfig -p` when available. - `python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())'`
- Fallback paths for common distros: - Copy the module/package into a game-local directory such as:
- `/usr/lib/libspeechd.so.2` (Arch-style) - `${installPath}/<GameRepoDir>/<RuntimePath>/.host-python/`
- `/usr/lib/x86_64-linux-gnu/libspeechd.so.2` (Debian/Ubuntu-style) - Fail with a clear message if import or copy fails.
- `/usr/lib64/libspeechd.so.2` and related `/lib*` fallbacks
- Copy resolved library into a game-local directory such as:
- `${installPath}/<GameRepoDir>/<RuntimePath>/.host-libs/libspeechd.so.2`
- Fail with a clear message if library is not found.
2. In launcher script: 2. In launcher script:
- Export `LD_LIBRARY_PATH` with the game-local `.host-libs` directory prepended. - Export `PYTHONPATH` with the game-local `.host-python` directory prepended.
- Launch via `uv run ...` from the same directory used for `uv sync`. - Launch via `uv run ...` from the same directory used for `uv sync`.
3. Removal safety: 3. Removal safety:
- Ensure first `installPath` line in launcher points to a path that lets `game_removal` infer the game root correctly. - Ensure first `installPath` line in launcher points to a path that lets `game_removal` infer the game root correctly.
- Do not put `installPath` in comments above that path line, because removal currently grabs the first matching line.
+30 -30
View File
@@ -1,17 +1,11 @@
check_dependencies git uv check_dependencies git uv python-speechd:speechd
# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh # shellcheck disable=SC2154 # set by linux-game-manager.sh
gameRoot="${installPath}/PlayPalace11" gameRoot="${installPath}/PlayPalace11"
desktopPath="${gameRoot}/clients/desktop" desktopPath="${gameRoot}/clients/desktop"
hostLibDir="${desktopPath}/.host-libs" hostPythonDir="${desktopPath}/.host-python"
speechdLibPath="" speechdFilePath=""
libCandidates=( speechdCopySourcePath=""
"/usr/lib/libspeechd.so.2"
"/usr/lib64/libspeechd.so.2"
"/usr/lib/x86_64-linux-gnu/libspeechd.so.2"
"/lib/x86_64-linux-gnu/libspeechd.so.2"
"/lib64/libspeechd.so.2"
)
if [[ -e "${gameRoot}" ]]; then if [[ -e "${gameRoot}" ]]; then
ui_msgbox "Game Installer" "Game Installer" "\"${gameRoot}\" already exists. Remove it first or choose a different game." ui_msgbox "Game Installer" "Game Installer" "\"${gameRoot}\" already exists. Remove it first or choose a different game."
@@ -40,30 +34,36 @@ if ! uv sync; then
fi fi
popd > /dev/null || exit 1 popd > /dev/null || exit 1
if command -v ldconfig > /dev/null 2>&1; then speechdFilePath="$(python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())' 2> /dev/null)"
speechdLibPath="$(ldconfig -p 2> /dev/null | awk '/libspeechd\.so\.2/{print $NF; exit}')" if [[ -z "${speechdFilePath}" ]]; then
fi ui_msgbox "Game Installer" "Game Installer" "Could not import python module speechd from host Python.\nInstall speech-dispatcher python bindings and try again."
if [[ -z "${speechdLibPath}" ]]; then
for libPath in "${libCandidates[@]}"; do
if [[ -r "${libPath}" ]]; then
speechdLibPath="${libPath}"
break
fi
done
fi
if [[ -z "${speechdLibPath}" ]]; then
ui_msgbox "Game Installer" "Game Installer" "Could not find libspeechd.so.2.\nInstall speech-dispatcher (Arch) or a libspeechd package (Debian/Ubuntu) and try again."
exit 1 exit 1
fi fi
mkdir -p "${hostLibDir}" || { if [[ "${speechdFilePath##*/}" == "__init__.py" ]]; then
ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostLibDir}." speechdCopySourcePath="${speechdFilePath%/*}"
elif [[ "${speechdFilePath##*/}" == "speechd.py" ]]; then
speechdCopySourcePath="${speechdFilePath}"
else
speechdCopySourcePath="${speechdFilePath}"
fi
if ! [[ -r "${speechdCopySourcePath}" ]]; then
ui_msgbox "Game Installer" "Game Installer" "Could not read speechd python binding at ${speechdCopySourcePath}."
exit 1
fi
mkdir -p "${hostPythonDir}" || {
ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostPythonDir}."
exit 1 exit 1
} }
if ! cp -Lf "${speechdLibPath}" "${hostLibDir}/libspeechd.so.2"; then if [[ -d "${speechdCopySourcePath}" ]]; then
ui_msgbox "Game Installer" "Game Installer" "Could not copy ${speechdLibPath} into ${hostLibDir}." if ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/"; then
ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd package into ${hostPythonDir}."
exit 1
fi
elif ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/speechd.py"; then
ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd module into ${hostPythonDir}."
exit 1 exit 1
fi fi
+4 -4
View File
@@ -1,17 +1,17 @@
check_dependencies uv check_dependencies uv
# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh # shellcheck disable=SC2154 # set by linux-game-manager.sh
gamePath="${installPath}/PlayPalace11/clients" gamePath="${installPath}/PlayPalace11/clients"
desktopPath="${gamePath}/desktop" desktopPath="${gamePath}/desktop"
hostLibDir="${desktopPath}/.host-libs" hostPythonDir="${desktopPath}/.host-python"
if ! [[ -d "${desktopPath}" ]]; then if ! [[ -d "${desktopPath}" ]]; then
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Play Palace is not installed at ${desktopPath}." ui_msgbox "Linux Game Manager" "Linux Game Manager" "Play Palace is not installed at ${desktopPath}."
exit 1 exit 1
fi fi
if [[ -d "${hostLibDir}" ]]; then if [[ -d "${hostPythonDir}" ]]; then
export LD_LIBRARY_PATH="${hostLibDir}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" export PYTHONPATH="${hostPythonDir}${PYTHONPATH:+:${PYTHONPATH}}"
fi fi
pushd "${desktopPath}" || exit 1 pushd "${desktopPath}" || exit 1