auto-commit for 39cc8e25-6412-479f-a29a-2a2bbf6e58ba

This commit is contained in:
emergent-agent-e1
2026-07-23 22:04:55 +00:00
parent 1471d58385
commit 34a052dabf
3 changed files with 218 additions and 4 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"env_image_name": "fastapi_react_mongo_shadcn_base_image_cloud_arm:release-17042026-1", "env_image_name": "fastapi_react_mongo_shadcn_base_image_cloud_arm:release-17042026-1",
"job_id": "08d9a7a1-2a0c-4502-9939-fc5d643c04c4", "job_id": "08d9a7a1-2a0c-4502-9939-fc5d643c04c4",
"created_at": "2026-07-23T21:54:52.675455+00:00Z" "created_at": "2026-07-23T22:02:35.449854+00:00Z"
} }
+24 -3
View File
@@ -3,10 +3,31 @@
A self-hosted Netflix-style streaming app for movies you legally own. A self-hosted Netflix-style streaming app for movies you legally own.
Built with FastAPI + React + MongoDB. Built with FastAPI + React + MongoDB.
## 📖 Deployment ## ⚡ One-line install (Proxmox / any Linux with root)
**→ See [DEPLOY.md](./DEPLOY.md) for full Proxmox + Docker Compose instructions** ```bash
(runs alongside your existing LAMP stack without conflicts). curl -fsSL https://raw.githubusercontent.com/YOU/kino-media-server/main/install.sh | sudo bash
```
Replace `YOU` with your GitHub username. The installer:
1. Installs Docker + Compose if missing
2. Clones the repo into `/opt/kino`
3. Generates a strong `JWT_SECRET` and admin password
4. Starts the stack via `docker compose`
5. Prints the URL + credentials
Non-interactive with overrides:
```bash
curl -fsSL https://raw.githubusercontent.com/YOU/kino-media-server/main/install.sh \
| sudo KINO_HTTP_PORT=9000 \
MEDIA_ROOT_HOST=/mnt/nas/movies \
ADMIN_PASSWORD='choose-your-own' \
bash
```
## 📖 Full deployment
See **[DEPLOY.md](./DEPLOY.md)** for LAMP-coexistence, Apache reverse proxy, Radarr integration, and firewalling.
## Features ## Features
Executable
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env bash
#
# Kino — 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/CHANGE_ME/kino-media-server.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@kino.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 — edit install.sh and set your GitHub URL, or pass KINO_REPO=... env var."
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 '━━━ Kino 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