Files
xpamych f069010250 Автоприменение HRIR: генерация PipeWire-конфига и перезапуск без ручных шагов
- Новый модуль surround.py: генерация конфига в ~/.config/lgcompanion/,
  симлинк в pipewire.conf.d, перезапуск PipeWire, удаление устаревшего
  симлинка headset-companion
- CLI: команда 'hrir apply [--no-restart]'; автоприменение в hrir add/
  set-default/remove
- install.sh использует 'lgcompanion hrir apply --no-restart' вместо
  inline-генерации в .generated/
- Тесты tests/test_surround.py
2026-09-14 21:29:18 +03:00

220 lines
9.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PYTHON="${PYTHON:-python3}"
# PREFIX: базовый префикс установки. По умолчанию ~/.local (пользовательская).
# DESTDIR: корень файловой системы для подготовки пакета (по умолчанию пустой).
PREFIX="${PREFIX:-${HOME}/.local}"
DESTDIR="${DESTDIR:-}"
# Определяем режим: пользовательский или системный.
USER_MODE=0
if [[ "${PREFIX}" == "${HOME}/.local" || "${PREFIX}" == "${HOME}"* ]]; then
USER_MODE=1
fi
echo "== Установщик LGCompanion =="
echo "PREFIX=${PREFIX}"
if [[ -n "${DESTDIR}" ]]; then
echo "DESTDIR=${DESTDIR}"
fi
if [[ "${USER_MODE}" -eq 1 ]]; then
echo "Режим: пользовательская установка"
else
echo "Режим: системная установка (пакетирование)"
fi
# 1. Проверка версии Python
PY_VERSION=$(${PYTHON} -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
PY_MAJOR=$(echo "${PY_VERSION}" | cut -d. -f1)
PY_MINOR=$(echo "${PY_VERSION}" | cut -d. -f2)
if [[ "${PY_MAJOR}" -lt 3 || ("${PY_MAJOR}" -eq 3 && "${PY_MINOR}" -lt 11) ]]; then
echo "ОШИБКА: требуется Python 3.11+ (найден ${PY_VERSION})"
exit 1
fi
# 2. Установка Python-пакета
if [[ "${USER_MODE}" -eq 1 ]]; then
if [[ -n "${VIRTUAL_ENV:-}" ]]; then
if command -v uv >/dev/null 2>&1; then
echo "Установка в активированное виртуальное окружение через uv..."
uv pip install -e "${SCRIPT_DIR}"
else
echo "Установка в активированное виртуальное окружение через pip..."
${PYTHON} -m pip install -e "${SCRIPT_DIR}"
fi
elif command -v pip3 >/dev/null 2>&1; then
echo "Установка через pip3 --user..."
pip3 install --user -e "${SCRIPT_DIR}"
export PATH="${HOME}/.local/bin:${PATH}"
else
echo "ОШИБКА: не найден pip3 и не активировано виртуальное окружение"
exit 1
fi
else
echo "Установка Python-пакета в ${DESTDIR}${PREFIX} ..."
${PYTHON} -m pip install --root="${DESTDIR}" --prefix="${PREFIX}" --ignore-installed "${SCRIPT_DIR}"
fi
# 3. Применяем конфиг PipeWire виртуального surround
if [[ "${USER_MODE}" -eq 1 ]]; then
# Пользовательский режим: генерация и симлинк выполняются самим приложением,
# чтобы GUI/CLI могли повторять это автоматически при смене HRIR.
if ! lgcompanion hrir apply --no-restart; then
echo "ПРЕДУПРЕЖДЕНИЕ: активный HRIR не задан или файл не найден."
echo " Виртуальный surround sink не будет создан."
echo " Добавьте HRIR командой: lgcompanion hrir add <path.wav>"
fi
else
HRIR_PATH=$(lgcompanion hrir active 2>/dev/null || true)
if [[ -z "${HRIR_PATH}" || ! -f "${HRIR_PATH}" ]]; then
echo "ПРЕДУПРЕЖДЕНИЕ: активный HRIR не задан или файл не найден."
echo " Виртуальный surround sink не будет создан."
echo " Добавьте HRIR командой: lgcompanion hrir add <path.wav>"
HRIR_PATH=""
fi
if [[ -n "${HRIR_PATH}" ]]; then
# Для системного пакета копируем HRIR в /usr/share/lgcompanion/
DATA_DIR="${DESTDIR}${PREFIX}/share/lgcompanion"
mkdir -p "${DATA_DIR}"
cp "${HRIR_PATH}" "${DATA_DIR}/hrir.wav"
HRIR_PATH="${PREFIX}/share/lgcompanion/hrir.wav"
echo "Скопирован HRIR: ${DATA_DIR}/hrir.wav"
CONFIG_DIR="${DESTDIR}${PREFIX}/share/pipewire/pipewire.conf.d"
CONFIG_GENERATED="${CONFIG_DIR}/lgcompanion-virtual-surround.conf"
CONFIG_TEMPLATE="${SCRIPT_DIR}/src/lgcompanion/data/virtual-surround-7.1.conf.template"
if [[ ! -f "${CONFIG_TEMPLATE}" ]]; then
echo "ОШИБКА: шаблон PipeWire-конфига не найден: ${CONFIG_TEMPLATE}"
exit 1
fi
mkdir -p "${CONFIG_DIR}"
${PYTHON} - "${CONFIG_TEMPLATE}" "${HRIR_PATH}" "${CONFIG_GENERATED}" <<'PY'
import sys
from pathlib import Path
template_path, hrir_path, out_path = sys.argv[1:]
text = Path(template_path).read_text()
Path(out_path).write_text(text.replace("{hrir_path}", hrir_path))
PY
echo "Установлен системный конфиг PipeWire: ${CONFIG_GENERATED}"
fi
fi
# 5. Создаём конфиг по умолчанию (только в пользовательском режиме)
if [[ "${USER_MODE}" -eq 1 ]]; then
lgcompanion config show >/dev/null 2>&1 || true
fi
# 6. systemd user service
SERVICE_TEMPLATE="${SCRIPT_DIR}/install/lgcompanion.service"
if [[ ! -f "${SERVICE_TEMPLATE}" ]]; then
echo "ОШИБКА: шаблон сервиса не найден: ${SERVICE_TEMPLATE}"
exit 1
fi
if [[ "${USER_MODE}" -eq 1 ]]; then
if [[ -n "${VIRTUAL_ENV:-}" ]]; then
CLI_EXEC="${VIRTUAL_ENV}/bin/lgcompanion"
else
CLI_EXEC="${HOME}/.local/bin/lgcompanion"
fi
else
CLI_EXEC="${PREFIX}/bin/lgcompanion"
fi
if [[ "${USER_MODE}" -eq 1 ]]; then
SYSTEMD_USER_DIR="${HOME}/.config/systemd/user"
mkdir -p "${SYSTEMD_USER_DIR}"
SERVICE_FILE="${SYSTEMD_USER_DIR}/lgcompanion.service"
${PYTHON} - "${SERVICE_TEMPLATE}" "${CLI_EXEC}" "${SERVICE_FILE}" <<'PY'
import sys
from pathlib import Path
template_path, exec_path, out_path = sys.argv[1:]
text = Path(template_path).read_text()
Path(out_path).write_text(text.replace("{exec_path}", exec_path))
PY
chmod 644 "${SERVICE_FILE}" 2>/dev/null || true
systemctl --user daemon-reload 2>/dev/null || true
systemctl --user enable lgcompanion.service 2>/dev/null || true
echo "Установлен и включён user service: ${SERVICE_FILE}"
else
SYSTEMD_SYSTEM_DIR="${DESTDIR}${PREFIX}/lib/systemd/user"
mkdir -p "${SYSTEMD_SYSTEM_DIR}"
SERVICE_FILE="${SYSTEMD_SYSTEM_DIR}/lgcompanion.service"
${PYTHON} - "${SERVICE_TEMPLATE}" "${CLI_EXEC}" "${SERVICE_FILE}" <<'PY'
import sys
from pathlib import Path
template_path, exec_path, out_path = sys.argv[1:]
text = Path(template_path).read_text()
Path(out_path).write_text(text.replace("{exec_path}", exec_path))
PY
chmod 644 "${SERVICE_FILE}" 2>/dev/null || true
echo "Установлен системный user service: ${SERVICE_FILE}"
fi
# 7. Иконка приложения
ICON_SRC="${SCRIPT_DIR}/src/lgcompanion/data/icon.svg"
if [[ ! -f "${ICON_SRC}" ]]; then
echo "ОШИБКА: иконка приложения не найдена: ${ICON_SRC}"
exit 1
fi
if [[ "${USER_MODE}" -eq 1 ]]; then
ICON_DIR="${HOME}/.local/share/icons/hicolor/scalable/apps"
else
ICON_DIR="${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps"
fi
mkdir -p "${ICON_DIR}"
cp "${ICON_SRC}" "${ICON_DIR}/lgcompanion.svg"
echo "Установлена иконка приложения: ${ICON_DIR}/lgcompanion.svg"
# 8. .desktop файл для меню приложений
DESKTOP_TEMPLATE="${SCRIPT_DIR}/install/lgcompanion.desktop"
if [[ "${USER_MODE}" -eq 1 ]]; then
if [[ -n "${VIRTUAL_ENV:-}" ]]; then
GUI_EXEC="${VIRTUAL_ENV}/bin/lgcompanion-gui"
else
GUI_EXEC="${HOME}/.local/bin/lgcompanion-gui"
fi
else
GUI_EXEC="${PREFIX}/bin/lgcompanion-gui"
fi
if [[ "${USER_MODE}" -eq 1 ]]; then
DESKTOP_DIR="${HOME}/.local/share/applications"
else
DESKTOP_DIR="${DESTDIR}${PREFIX}/share/applications"
fi
mkdir -p "${DESKTOP_DIR}"
DESKTOP_FILE="${DESKTOP_DIR}/lgcompanion.desktop"
${PYTHON} - "${DESKTOP_TEMPLATE}" "${GUI_EXEC}" "${DESKTOP_FILE}" <<'PY'
import sys
from pathlib import Path
template_path, exec_path, out_path = sys.argv[1:]
text = Path(template_path).read_text()
Path(out_path).write_text(text.replace("{exec_path}", exec_path))
PY
chmod 644 "${DESKTOP_FILE}" 2>/dev/null || true
echo "Создан .desktop файл: ${DESKTOP_FILE}"
if [[ "${USER_MODE}" -eq 1 ]]; then
echo ""
echo "Установка завершена."
echo "Перезапустите PipeWire, чтобы загрузить виртуальный surround sink:"
echo " systemctl --user restart pipewire pipewire-pulse wireplumber"
echo "Затем запустите демон:"
echo " systemctl --user start lgcompanion.service"
echo "Или вручную:"
echo " lgcompanion run -v"
echo ""
echo "Для запуска GUI:"
echo " lgcompanion-gui"
else
echo ""
echo "Системная установка завершена."
echo "Не забудьте обновить базу данных desktop-файлов:"
echo " update-desktop-database ${PREFIX}/share/applications"
fi