Files
pipu-music/deploy/install.sh
T
mrleo1nidandClaude Opus 5.5 8b76aa3964
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 55s
ci / ts / ts (packages + web) (push) Successful in 1m0s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 34s
ci / api / api (push) Successful in 26s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 34s
feat: album covers with palettes and signed links (M2)
- covers are taken from the embedded picture of the first track or a
  cover/folder/front image in the album folder, converted by ffmpeg to
  WebP 64/300/1200 and named by content hash, so albums sharing a cover
  share the files; a full scan looks again for albums without one
- a 3-colour palette (dominant, second, most saturated accent) from a
  deterministic k-means feeds placeholders, page tints and the wave
- /covers/{id} is public but HMAC-signed and immutable; nginx serves
  the file via X-Accel-Redirect, X_ACCEL=false serves it from api
- the web client picks the size by display size and pixel density
- install.sh and update.sh generate STREAM_SIGNING_KEY

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:06:15 +03:00

89 lines
4.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Первичная подготовка сервера: каталоги данных, общий корень библиотеки с mount propagation, .env с секретами.
# Запуск: sudo ./install.sh (повторный запуск безопасен)
set -euo pipefail
cd "$(dirname "$0")"
# .env и каталоги создаются от root, но сам репозиторий должен остаться у пользователя, который делает git pull.
OWNER="${SUDO_USER:-root}"
DATA="${PIPU_DATA:-/srv/pipu}"
echo "→ каталоги в $DATA"
mkdir -p "$DATA"/{library,library-host,cache/transcode,cache/covers,postgres,meili,redis,models,updates,uploads,backups,caddy/data,caddy/config}
# Каталоги, куда пишут сервисы без root: api (distroless nonroot, uid 65532) и analyzer (uid 10001).
# Без рекурсии: файлы внутри создают сами сервисы, а повторный запуск не обходит весь кэш.
chown 65532:65532 "$DATA"/{cache,cache/transcode,cache/covers,updates,uploads}
chown 10001:10001 "$DATA/models"
# Папка с локальной музыкой: sudo LIBRARY_HOST=/mnt/music ./install.sh (или LIBRARY_HOST в .env)
LIBRARY_HOST="${LIBRARY_HOST:-$( [ -f .env ] && sed -n 's/^LIBRARY_HOST=//p' .env || true )}"
if [ -n "$LIBRARY_HOST" ]; then
if [ ! -d "$LIBRARY_HOST" ]; then
echo "LIBRARY_HOST=$LIBRARY_HOST: каталога нет — смонтируйте диск с музыкой (docs/install-guide.md, шаг 4)" >&2
exit 1
fi
findmnt -n --target "$LIBRARY_HOST" -o TARGET,SOURCE | sed 's/^/→ музыка: /'
fi
# storage-agent монтирует NFS внутрь $DATA/library; чтобы точки монтирования видели другие контейнеры,
# каталог должен быть отдельной точкой монтирования с shared propagation.
if ! findmnt -n "$DATA/library" >/dev/null 2>&1; then
echo "→ bind-mount $DATA/library (rshared)"
mount --bind "$DATA/library" "$DATA/library"
fi
mount --make-rshared "$DATA/library"
UNIT=/etc/systemd/system/pipu-library-mount.service
if [ -d /etc/systemd/system ] && [ ! -f "$UNIT" ]; then
echo "→ systemd-юнит $UNIT (повторяет bind-mount после перезагрузки)"
cat > "$UNIT" <<EOF
[Unit]
Description=Pipu Music library mount propagation
Before=docker.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'findmnt -n "$DATA/library" || mount --bind "$DATA/library" "$DATA/library"; mount --make-rshared "$DATA/library"'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable pipu-library-mount.service
fi
secret() { head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 40; }
if [ ! -f .env ]; then
echo "→ .env из .env.example"
cp .env.example .env
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(secret)|; s|^MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(secret)|; s|^INTERNAL_TOKEN=.*|INTERNAL_TOKEN=$(secret)|; s|^PIPU_DATA=.*|PIPU_DATA=$DATA|; s|^LIBRARY_HOST=.*|LIBRARY_HOST=$LIBRARY_HOST|" .env
chmod 600 .env
chown "$OWNER" .env
echo " Заполните в .env: DOMAIN и ACME_EMAIL (или настройте свой прокси — docs/install-guide.md)"
fi
# Ключи подписи (токены — M1, ссылки на обложки и аудио — M2): создаются один раз,
# в том числе в .env, сделанном до их появления.
for key in JWT_PRIVATE_KEY STREAM_SIGNING_KEY; do
if ! grep -q "^$key=." .env; then
sed -i "/^$key=\$/d" .env
echo "$key=$(head -c 32 /dev/urandom | base64)" >> .env
echo "→ в .env добавлен $key"
fi
done
# LIBRARY_HOST, переданный при повторном запуске, попадает и в уже существующий .env
if [ -n "$LIBRARY_HOST" ]; then
if grep -q '^LIBRARY_HOST=' .env; then
sed -i "s|^LIBRARY_HOST=.*|LIBRARY_HOST=$LIBRARY_HOST|" .env
else
echo "LIBRARY_HOST=$LIBRARY_HOST" >> .env
fi
fi
echo "Готово. Сборка и запуск последнего релиза: ./update.sh"