Initial commit: Shelfless – alternative Audiobookshelf frontend
React + Vite + TypeScript SPA covering the full ABS feature set (library browsing, item detail, metadata/cover editing, podcasts, player with session sync, admin: users/libraries/scanner/server settings). Dev uses a dynamic CORS proxy; production is served by server/index.mjs (static + reverse proxy to ABS_URL). Includes systemd unit and installer under deploy/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
60
deploy/README.md
Normal file
60
deploy/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Deployment (Proxmox LXC, auto-start)
|
||||
|
||||
Shelfless runs as a small Node server that serves the built SPA **and** reverse-proxies
|
||||
the ABS API. So the browser only ever talks to Shelfless (one origin → no CORS), and the
|
||||
Audiobookshelf address is fixed by the deployment (`ABS_URL`) — users only log in.
|
||||
|
||||
## 1. Prerequisites on the container
|
||||
```bash
|
||||
apt update && apt install -y nodejs npm git # Node 18+ (20+ recommended)
|
||||
node --version
|
||||
```
|
||||
|
||||
## 2. Get the code & build
|
||||
```bash
|
||||
mkdir -p /opt/shelfless && cd /opt/shelfless
|
||||
# copy the project here (git clone / scp / rsync), then:
|
||||
npm ci
|
||||
npm run build # produces dist/
|
||||
```
|
||||
|
||||
## 3. Configure the ABS target
|
||||
The server reads these env vars (see the systemd unit):
|
||||
- `ABS_URL` — the Audiobookshelf server, e.g. `http://127.0.0.1:13378` (same container)
|
||||
or `http://192.168.1.71:13378` (another host).
|
||||
- `PORT` — the port Shelfless listens on (default `8080`).
|
||||
- `HOST` — bind address (default `0.0.0.0`).
|
||||
|
||||
Quick manual test:
|
||||
```bash
|
||||
ABS_URL=http://127.0.0.1:13378 PORT=8080 npm start
|
||||
# open http://<container-ip>:8080
|
||||
```
|
||||
|
||||
## 4. Auto-start with systemd
|
||||
```bash
|
||||
cp deploy/shelfless.service /etc/systemd/system/shelfless.service
|
||||
# edit WorkingDirectory / ABS_URL / PORT inside the file if needed
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shelfless
|
||||
systemctl status shelfless # check it's running
|
||||
journalctl -u shelfless -f # logs
|
||||
```
|
||||
|
||||
Open `http://<container-ip>:8080`. The setup screen asks only for username + password
|
||||
(the server URL is fixed). "Angemeldet bleiben" keeps you logged in across reloads;
|
||||
otherwise you log in each session.
|
||||
|
||||
## Updating
|
||||
```bash
|
||||
cd /opt/shelfless
|
||||
git pull # or copy new files
|
||||
npm ci && npm run build
|
||||
systemctl restart shelfless
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Put it behind a reverse proxy (nginx/Caddy/Traefik) for HTTPS + a domain if you expose
|
||||
it beyond the LAN.
|
||||
- Proxied paths: `/api`, `/login`, `/logout`, `/public`, `/status`, `/hls`, `/feed`,
|
||||
`/socket.io`. Everything else is served from `dist/` (SPA fallback to `index.html`).
|
||||
75
deploy/install.sh
Normal file
75
deploy/install.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shelfless installer for a Debian/Ubuntu Proxmox LXC.
|
||||
# Installs Node, fetches the repo, builds the frontend, and sets up a systemd service
|
||||
# that serves the app and reverse-proxies to your Audiobookshelf server.
|
||||
#
|
||||
# Usage (as root on the container):
|
||||
# REPO_URL=https://git.scarriffle.com/<owner>/shelfless.git \
|
||||
# ABS_URL=http://127.0.0.1:13378 PORT=8080 \
|
||||
# bash install.sh
|
||||
#
|
||||
# Re-running updates an existing install.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_URL="${REPO_URL:?Set REPO_URL to your git repo, e.g. https://git.scarriffle.com/owner/shelfless.git}"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/shelfless}"
|
||||
ABS_URL="${ABS_URL:-http://127.0.0.1:13378}"
|
||||
PORT="${PORT:-8080}"
|
||||
SERVICE="${SERVICE:-shelfless}"
|
||||
|
||||
echo "==> Installing system dependencies"
|
||||
apt-get update -y
|
||||
apt-get install -y git curl ca-certificates
|
||||
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
echo "==> Installing Node.js 20.x"
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||
apt-get install -y nodejs
|
||||
fi
|
||||
echo " node $(node --version), npm $(npm --version)"
|
||||
|
||||
echo "==> Fetching source into $INSTALL_DIR"
|
||||
if [ -d "$INSTALL_DIR/.git" ]; then
|
||||
git -C "$INSTALL_DIR" pull --ff-only
|
||||
else
|
||||
git clone "$REPO_URL" "$INSTALL_DIR"
|
||||
fi
|
||||
|
||||
echo "==> Building"
|
||||
cd "$INSTALL_DIR"
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
echo "==> Writing systemd unit /etc/systemd/system/$SERVICE.service"
|
||||
NODE_BIN="$(command -v node)"
|
||||
cat > "/etc/systemd/system/$SERVICE.service" <<EOF
|
||||
[Unit]
|
||||
Description=Shelfless (Audiobookshelf frontend)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$INSTALL_DIR
|
||||
ExecStart=$NODE_BIN server/index.mjs
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=$PORT
|
||||
Environment=ABS_URL=$ABS_URL
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "==> Enabling and starting service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now "$SERVICE"
|
||||
sleep 1
|
||||
systemctl --no-pager --full status "$SERVICE" || true
|
||||
|
||||
IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
echo ""
|
||||
echo "Done. Shelfless is running:"
|
||||
echo " URL: http://${IP:-<container-ip>}:$PORT"
|
||||
echo " ABS: $ABS_URL"
|
||||
echo " Logs: journalctl -u $SERVICE -f"
|
||||
24
deploy/shelfless.service
Normal file
24
deploy/shelfless.service
Normal file
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Shelfless (Audiobookshelf frontend)
|
||||
After=network.target
|
||||
# If Audiobookshelf runs on the same container, start after it:
|
||||
# After=network.target audiobookshelf.service
|
||||
# Wants=audiobookshelf.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# Adjust to where you copied the project:
|
||||
WorkingDirectory=/opt/shelfless
|
||||
ExecStart=/usr/bin/node server/index.mjs
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=8080
|
||||
# The Audiobookshelf server this frontend talks to (same container = localhost):
|
||||
Environment=ABS_URL=http://127.0.0.1:13378
|
||||
# Optional hardening:
|
||||
# User=shelfless
|
||||
# Group=shelfless
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user