117 lines
4.0 KiB
Bash
Executable File
117 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
export WINEPREFIX="${WINEPREFIX:-${HOME}/.local/wine64}"
|
|
export WINEDEBUG="${WINEDEBUG:--all}"
|
|
|
|
installerUrl="${WINESPEAK_INSTALLER_URL:-https://stormgames.wolfe.casa/downloads/winespeak.exe}"
|
|
installerName="winespeak.exe"
|
|
installerSha256="${WINESPEAK_INSTALLER_SHA256:-8007004cd024b391e8f1962455ffe2a8b241cfdf52641a2bc1aa2274bc80f236}"
|
|
cacheDir="${XDG_CACHE_HOME:-${HOME}/.cache}/audiogame-manager"
|
|
installerPath="${cacheDir}/${installerName}"
|
|
partialPath="${installerPath}.part"
|
|
wrapperPath="${WINEPREFIX}/drive_c/Program Files (x86)/espeak-ng-sapi/EspeakSAPI.dll"
|
|
wrapperSha256="2282da4a23f18b40e6601a4b9a880f484196bf2f5138881e76428be10d8dbe76"
|
|
cscriptPath="${WINEPREFIX}/drive_c/windows/syswow64/cscript.exe"
|
|
verifyScriptPath="${WINEPREFIX}/drive_c/windows/temp/verify_winespeak.vbs"
|
|
voiceToken="HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\Espeak-ng US English"
|
|
|
|
fail() {
|
|
printf 'Error: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_command() {
|
|
command -v "$1" > /dev/null 2>&1 || fail "Required command not found: $1"
|
|
}
|
|
|
|
verify_sha256() {
|
|
local file="$1"
|
|
local expected="$2"
|
|
local actual
|
|
|
|
actual="$(sha256sum "$file" | awk '{print $1}')"
|
|
[[ "$actual" == "$expected" ]]
|
|
}
|
|
|
|
download_installer() {
|
|
mkdir -p "$cacheDir"
|
|
|
|
if [[ -s "$installerPath" ]] && verify_sha256 "$installerPath" "$installerSha256"; then
|
|
printf 'Using cached WineSpeak installer.\n'
|
|
return
|
|
fi
|
|
|
|
rm -f "$installerPath" "$partialPath"
|
|
printf 'Downloading WineSpeak...\n'
|
|
if ! curl -L4 --fail --retry 3 --output "$partialPath" "$installerUrl"; then
|
|
rm -f "$partialPath"
|
|
fail 'Could not download WineSpeak.'
|
|
fi
|
|
|
|
if ! verify_sha256 "$partialPath" "$installerSha256"; then
|
|
rm -f "$partialPath"
|
|
fail 'The downloaded WineSpeak installer failed its SHA-256 check.'
|
|
fi
|
|
|
|
mv "$partialPath" "$installerPath"
|
|
}
|
|
|
|
install_winespeak() {
|
|
local registryOutput
|
|
local voiceOutput
|
|
|
|
download_installer
|
|
|
|
wineserver -k || true
|
|
printf 'Installing WineSpeak into %s...\n' "$WINEPREFIX"
|
|
if ! wine "$installerPath" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-; then
|
|
fail 'WineSpeak installation failed.'
|
|
fi
|
|
|
|
if [[ ! -f "$wrapperPath" ]]; then
|
|
fail 'WineSpeak did not install its 32-bit SAPI wrapper.'
|
|
fi
|
|
if ! verify_sha256 "$wrapperPath" "$wrapperSha256"; then
|
|
fail 'WineSpeak installed an unexpected 32-bit SAPI wrapper.'
|
|
fi
|
|
|
|
printf 'Setting WineSpeak US English as the default SAPI voice...\n'
|
|
if ! wine reg add 'HKCU\Software\Microsoft\Speech\Voices' \
|
|
/v DefaultTokenId /t REG_SZ /d "$voiceToken" /f > /dev/null; then
|
|
fail 'Could not set the default SAPI voice.'
|
|
fi
|
|
|
|
registryOutput="$(wine reg query 'HKCU\Software\Microsoft\Speech\Voices' /v DefaultTokenId 2>/dev/null)"
|
|
if ! grep -Fq "$voiceToken" <<< "$registryOutput"; then
|
|
fail 'Could not verify the default SAPI voice.'
|
|
fi
|
|
|
|
if [[ ! -f "$cscriptPath" ]]; then
|
|
fail "Wine's 32-bit cscript.exe was not found. Install speechsdk in this prefix first."
|
|
fi
|
|
mkdir -p "${verifyScriptPath%/*}"
|
|
printf '%s\n' \
|
|
'dim speechobject' \
|
|
'set speechobject=createobject("sapi.spvoice")' \
|
|
'wscript.echo speechobject.voice.getdescription' > "$verifyScriptPath"
|
|
if ! voiceOutput="$(wine "$cscriptPath" //nologo 'c:\windows\temp\verify_winespeak.vbs' 2>&1)"; then
|
|
fail "WineSpeak's 32-bit SAPI voice could not be created: ${voiceOutput}"
|
|
fi
|
|
if ! grep -Fq 'Espeak-ng US English' <<< "$voiceOutput"; then
|
|
fail "WineSpeak's 32-bit SAPI verification returned an unexpected voice: ${voiceOutput}"
|
|
fi
|
|
|
|
printf 'WineSpeak is installed and US English is the default SAPI voice.\n'
|
|
}
|
|
|
|
if [[ ! -d "${WINEPREFIX}/drive_c" ]]; then
|
|
fail "Wine prefix does not exist: ${WINEPREFIX}"
|
|
fi
|
|
|
|
for commandName in curl wine wineserver sha256sum awk grep; do
|
|
require_command "$commandName"
|
|
done
|
|
|
|
install_winespeak
|