Files
Myron Blair e27bb37f7b Rebrand StreamHoard, strip Emergent.sh platform artifacts
- Remove .emergent/ state dir, tracked .gitconfig, @emergentbase/visual-edits
  dep + craco wiring, emergent.sh script/meta tags, PostHog telemetry snippet
- Rename UI/docs branding Kino -> StreamHoard (README, DEPLOY.md, Navbar,
  Login, Register, AdminShowEpisodes, FastAPI title, health check response)
- Rename docker-compose container/network names to streamhoard-*
- Default admin email domain -> admin@streamhoard.local
2026-07-23 20:20:29 -05:00

194 lines
6.1 KiB
Bash
Executable File
Raw Permalink 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
#
# StreamHoard — one-line installer
#
# Usage (interactive):
# curl -fsSL https://raw.githubusercontent.com/YOU/kino-media-server/main/install.sh | sudo bash
#
# Usage (non-interactive, override defaults with env):
# curl -fsSL .../install.sh | sudo KINO_HTTP_PORT=9000 MEDIA_ROOT_HOST=/mnt/nas/movies bash
#
# What it does:
# 1. Installs Docker + Compose if missing (apt/dnf/yum)
# 2. Clones the repo into $KINO_DIR (default /opt/kino)
# 3. Generates a strong JWT_SECRET and (if omitted) ADMIN_PASSWORD
# 4. Writes .env
# 5. Runs `docker compose up -d`
# 6. Prints URL + credentials
#
set -euo pipefail
# ---------- Defaults (override via env) ----------
KINO_REPO="${KINO_REPO:-https://github.com/myronblair/kino-app.git}"
KINO_BRANCH="${KINO_BRANCH:-main}"
KINO_DIR="${KINO_DIR:-/opt/kino}"
KINO_HTTP_PORT="${KINO_HTTP_PORT:-8080}"
MEDIA_ROOT_HOST="${MEDIA_ROOT_HOST:-${KINO_DIR}/media}"
DB_NAME="${DB_NAME:-kino}"
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@streamhoard.local}"
ADMIN_NAME="${ADMIN_NAME:-Admin}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-}"
JWT_SECRET="${JWT_SECRET:-}"
# ---------- Pretty output ----------
c_red() { printf "\033[31m%s\033[0m" "$*"; }
c_grn() { printf "\033[32m%s\033[0m" "$*"; }
c_ylw() { printf "\033[33m%s\033[0m" "$*"; }
c_cyn() { printf "\033[36m%s\033[0m" "$*"; }
say() { printf "%s %s\n" "$(c_cyn '')" "$*"; }
ok() { printf "%s %s\n" "$(c_grn '✓')" "$*"; }
warn() { printf "%s %s\n" "$(c_ylw '!')" "$*"; }
die() { printf "%s %s\n" "$(c_red '✗')" "$*" >&2; exit 1; }
# ---------- Preflight ----------
[ "$(id -u)" -eq 0 ] || die "Run as root (or via sudo). Try: curl -fsSL ... | sudo bash"
if [ "$KINO_REPO" = "https://github.com/CHANGE_ME/kino-media-server.git" ]; then
die "KINO_REPO placeholder — pass KINO_REPO=... env var to install.sh"
fi
# ---------- OS detection & package manager ----------
if [ -r /etc/os-release ]; then . /etc/os-release; fi
OS_ID="${ID:-unknown}"
say "Detected OS: ${OS_ID} ${VERSION_ID:-}"
pkg_install() {
if command -v apt-get >/dev/null 2>&1; then
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "$@"
elif command -v dnf >/dev/null 2>&1; then
dnf install -y "$@"
elif command -v yum >/dev/null 2>&1; then
yum install -y "$@"
else
die "No supported package manager (apt/dnf/yum) found."
fi
}
# ---------- Ensure prerequisites ----------
need_pkgs=()
command -v curl >/dev/null 2>&1 || need_pkgs+=(curl)
command -v git >/dev/null 2>&1 || need_pkgs+=(git)
command -v openssl >/dev/null 2>&1 || need_pkgs+=(openssl)
command -v ca-certificates >/dev/null 2>&1 || need_pkgs+=(ca-certificates)
if [ ${#need_pkgs[@]} -gt 0 ]; then
say "Installing prerequisites: ${need_pkgs[*]}"
pkg_install "${need_pkgs[@]}" >/dev/null
ok "Prerequisites installed"
fi
# ---------- Docker ----------
if ! command -v docker >/dev/null 2>&1; then
say "Installing Docker via official convenience script"
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
ok "Docker installed"
else
ok "Docker already installed ($(docker --version))"
fi
if ! docker compose version >/dev/null 2>&1; then
# docker compose plugin missing — install
say "Installing docker compose plugin"
if command -v apt-get >/dev/null 2>&1; then
pkg_install docker-compose-plugin >/dev/null
else
die "docker compose plugin not found — install it manually for your distro."
fi
ok "Compose plugin installed"
else
ok "Docker Compose already available ($(docker compose version --short))"
fi
# ---------- Clone or update repo ----------
if [ -d "$KINO_DIR/.git" ]; then
say "Updating existing checkout at $KINO_DIR"
git -C "$KINO_DIR" fetch --quiet origin "$KINO_BRANCH"
git -C "$KINO_DIR" checkout --quiet "$KINO_BRANCH"
git -C "$KINO_DIR" pull --quiet --ff-only origin "$KINO_BRANCH" || warn "git pull skipped (local changes?)"
else
say "Cloning $KINO_REPO$KINO_DIR"
mkdir -p "$(dirname "$KINO_DIR")"
git clone --depth 1 --branch "$KINO_BRANCH" "$KINO_REPO" "$KINO_DIR"
ok "Repo cloned"
fi
cd "$KINO_DIR"
# ---------- Media root ----------
mkdir -p "$MEDIA_ROOT_HOST"
ok "Media dir ready: $MEDIA_ROOT_HOST"
# ---------- Secrets ----------
if [ -z "$JWT_SECRET" ]; then
JWT_SECRET="$(openssl rand -hex 32)"
ok "Generated random JWT_SECRET"
fi
if [ -z "$ADMIN_PASSWORD" ]; then
ADMIN_PASSWORD="$(openssl rand -base64 18 | tr -d '/+=' | cut -c1-20)"
GENERATED_PASSWORD=1
ok "Generated random ADMIN_PASSWORD"
fi
# ---------- Write .env ----------
if [ -f .env ]; then
cp .env ".env.bak.$(date +%Y%m%d%H%M%S)"
warn ".env exists — backed up. Overwriting with new values."
fi
cat > .env <<EOF
# Auto-generated by install.sh on $(date -Iseconds)
KINO_HTTP_PORT=${KINO_HTTP_PORT}
MEDIA_ROOT_HOST=${MEDIA_ROOT_HOST}
DB_NAME=${DB_NAME}
JWT_SECRET=${JWT_SECRET}
JWT_EXPIRE_HOURS=720
ADMIN_EMAIL=${ADMIN_EMAIL}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
ADMIN_NAME=${ADMIN_NAME}
EOF
chmod 600 .env
ok "Wrote $KINO_DIR/.env (chmod 600)"
# ---------- Build & start ----------
say "Building images (first run may take a few minutes — ffmpeg, node build)"
docker compose build --pull
say "Starting containers"
docker compose up -d
sleep 4
# ---------- Health check ----------
HOST_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
[ -z "$HOST_IP" ] && HOST_IP="localhost"
URL="http://${HOST_IP}:${KINO_HTTP_PORT}"
if curl -fsS --max-time 10 "http://localhost:${KINO_HTTP_PORT}/api/" >/dev/null 2>&1; then
ok "Backend healthy at $URL/api/"
else
warn "Backend not responding yet — check: cd $KINO_DIR && docker compose logs -f backend"
fi
# ---------- Done ----------
cat <<EOF
$(c_grn '━━━ StreamHoard is up ━━━')
URL : $(c_cyn "$URL")
Admin : $(c_cyn "$ADMIN_EMAIL")
Password : $(c_cyn "$ADMIN_PASSWORD")
Config : ${KINO_DIR}/.env
Media : ${MEDIA_ROOT_HOST}
$(c_ylw 'Save the password now — it is only printed once.')
Manage:
cd $KINO_DIR
docker compose logs -f backend # live logs
docker compose down # stop
docker compose up -d # start
docker compose pull && docker compose up -d --build # update
Full docs: $KINO_DIR/DEPLOY.md
EOF