{"id":49524415,"url":"https://github.com/showpilotfpp/showpilot","last_synced_at":"2026-05-24T02:00:43.401Z","repository":{"id":353683189,"uuid":"1220417412","full_name":"ShowPilotFPP/ShowPilot","owner":"ShowPilotFPP","description":"Self-hosted Remote Falcon alternative for FPP — queue, control, and stream all in one place","archived":false,"fork":false,"pushed_at":"2026-05-18T23:08:03.000Z","size":1545,"stargazers_count":5,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-05-19T01:31:58.010Z","etag":null,"topics":["christmas-lights","docker","falcon-pi-player","fpp","light-show","nodejs","self-hosted","xlights"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ShowPilotFPP.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-24T22:02:13.000Z","updated_at":"2026-05-18T23:08:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ShowPilotFPP/ShowPilot","commit_stats":null,"previous_names":["frankietest6/openfalcon","ofplugin/openfalcon","showpilotfpp/showpilot"],"tags_count":244,"template":false,"template_full_name":null,"purl":"pkg:github/ShowPilotFPP/ShowPilot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShowPilotFPP%2FShowPilot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShowPilotFPP%2FShowPilot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShowPilotFPP%2FShowPilot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShowPilotFPP%2FShowPilot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ShowPilotFPP","download_url":"https://codeload.github.com/ShowPilotFPP/ShowPilot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShowPilotFPP%2FShowPilot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33418550,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"online","status_checked_at":"2026-05-24T02:00:06.296Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["christmas-lights","docker","falcon-pi-player","fpp","light-show","nodejs","self-hosted","xlights"],"created_at":"2026-05-02T02:02:22.250Z","updated_at":"2026-05-24T02:00:43.393Z","avatar_url":"https://github.com/ShowPilotFPP.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ShowPilot\n\n[![Website](https://img.shields.io/badge/Website-showpilot.dev-ffb155?logo=googlechrome\u0026logoColor=white)](https://showpilot.dev) [![Discord](https://img.shields.io/badge/Discord-Join%20the%20chat-5865F2?logo=discord\u0026logoColor=white)](https://discord.gg/UpmcXmWfN9) [![Facebook](https://img.shields.io/badge/Facebook-Join%20the%20group-1877F2?logo=facebook\u0026logoColor=white)](https://www.facebook.com/groups/showpilot)\n\n**Self-hosted light show viewer control server.** A drop-in alternative to Remote Falcon for hobbyists who want to run their own infrastructure without relying on a cloud service.\n\nShowPilot pairs with a Falcon Player (FPP) plugin to let your visitors:\n- 🎵 Vote for sequences (Voting mode) or queue them up (Jukebox mode)\n- 📱 Listen to your show audio on their phone via a built-in web player — no app required\n- 🎄 See what's playing now and what's coming up next on a customizable viewer page\n\nYou get an admin dashboard with stats, queue management, sequence configuration, viewer-page editor, theming, and multi-user authentication.\n\n\u003e **Migrating from Remote Falcon?** ShowPilot's viewer page renderer is fully compatible with Remote Falcon templates. All the standard placeholders (`{PLAYLISTS}`, `{NOW_PLAYING}`, `{JUKEBOX_QUEUE}`, `{NEXT_PLAYLIST}`, `{QUEUE_DEPTH}`, `{LOCATION_CODE}`, etc.) and mode containers (`{playlist-voting-dynamic-container}`, `{jukebox-dynamic-container}`, `{after-hours-message}`, `{location-code-dynamic-container}`) work identically. Paste your existing Remote Falcon viewer HTML into ShowPilot's editor and it just works — no template rewrite needed. If something doesn't render quite right out of the box (older RF templates sometimes lack a few of the toast hooks or the after-hours setup ShowPilot expects), drop your HTML into the [RF Template Converter](https://showpilot.dev/convert) — it adds the missing pieces, flags layout traps, and gives you back a paste-ready ShowPilot template.\n\n---\n\n## Features\n\n### Visitor experience\n\n- **Voting \u0026 Jukebox modes** — switch between letting viewers vote for the next sequence or queue songs to play in order\n- **Listen-on-Phone audio player** — built-in web audio streaming directly from FPP. Visitors hear synchronized show audio on their phones with no native app, no extra service, no Icecast setup. Works on iOS Safari, Android Chrome, and desktop browsers\n- **Mobile-first viewer page** — designed for cold winter hands tapping with gloves. Large hit targets, high-contrast cards, marquee-scrolling long titles, optional snow effects, optional themed player decorations (Christmas, Halloween, Easter, St. Patrick's, Independence Day, Valentine's, Hanukkah, Thanksgiving, generic snow)\n- **Cover art support** — automatic MusicBrainz/iTunes cover lookup per sequence with admin override, displayed inline on song cards\n- **Now Playing + Up Next** — real-time updates pushed via Socket.io, plus polled fallback for slower connections\n\n### Visual page designer\n\n- **Three editing modes** — pick what fits your comfort level:\n  - **Settings mode**: form-based editor for show name, colors, fonts, hours, social links, FM frequency. No HTML knowledge required\n  - **Blocks mode**: drag-and-drop sections onto a canvas — 12 block types covering Hero, Text, Divider, Show Hours, Now Playing, Queue, Voting Instructions, Jukebox Instructions, Song List, Location Code, Social Links, and Custom HTML. Reorder by dragging or with arrow buttons\n  - **Code mode**: full Monaco editor for hand-written HTML. Standard Remote Falcon placeholders supported\n- **Live preview iframe** — see your changes update next to the editor as you type, before committing\n- **Drafts** — edits save as drafts automatically (debounced 500ms). Visitors keep seeing the live page until you click Save Changes\n- **Multiple templates** — create as many templates as you want and switch active ones with one click. Build separate looks for different seasons or events\n- **Default template included** — fresh installs get a working mobile-friendly template seeded automatically; customize from there\n\n### Audio \u0026 copyright safeguards\n\n- **GPS audio gate (optional)** — restrict audio playback to listeners physically present at your show. Tapping the 🎧 button forces a fresh GPS check (cached location won't bypass it). Re-verifies every 15 minutes during playback to catch listeners who walked away\n- **Refresh-to-recover latch** — once the gate trips, audio stays blocked until the page is refreshed. Prevents auto-resume when admin toggles control modes\n- **External audio access** — set your public domain so listeners on cellular can stream the audio without VPN. Local listeners still use the direct path for best performance\n\n### Location tools\n\n- **Address-to-coordinates lookup** — type any address (\"1234 Main St, Branson MO\"), click Find Coordinates, lat/lng auto-fill. Powered by OpenStreetMap Nominatim\n- **Detect-my-location button** — uses browser GPS to set show coordinates if you're at the venue\n- **Visual map preview** — embedded OpenStreetMap shows exactly where your coordinates point, scales to your radius. Verify your config without leaving admin\n\n### FPP integration\n\n- **Companion FPP plugin** — install the ShowPilot plugin from FPP's Plugin Manager, point it at your ShowPilot server URL, and it stays connected. Plugin handles sequence sync, playing-status reporting, and viewer request handoff to FPP's playlist\n- **Sequence sync** — sequences imported from FPP into the admin, where you can reorder, rename for display, set artists, hide individual sequences, and toggle votable/jukeboxable per sequence\n- **Mid-track resume** — when a viewer-requested song interrupts the original, resuming the original picks up at the correct elapsed position (not the start)\n- **PSA injection** — auto-inject PSAs (sponsor messages, holiday greetings) every N interactions\n- **Real-time plugin status** — admin header shows whether FPP plugin is connected and last sync time, updated live via Socket.io\n\n### Admin \u0026 operations\n\n- **Multi-user authentication** — username + password, bcrypt hashed, JWT session cookies. Per-user \"remember me\" (30-day cookie or session-only). Force-password-change flag for new accounts\n- **User management** — add/edit/disable/delete users. Self-protection: can't disable yourself, can't delete the last user\n- **Themes** — Stage·Dark and Stage·Light core themes for the admin UI, plus seasonal variants (Christmas, Halloween, Easter, St. Patrick's, Independence Day, Valentine's) you can switch between\n- **Sequence snapshots** — save your current playlist configuration (display names, artists, sort order, visibility) as a named snapshot. Restore later when switching seasons. Non-destructive: preserves play history, vote stats, queue state\n- **Live stats dashboard** — votes per round, jukebox queue depth, plays per sequence, last-played times, viewer count\n- **IP blocking** — block individual IPs or CIDR ranges. Useful when one user gets too enthusiastic with the request button\n- **Per-sequence visibility/votability/jukeboxability** — fine-grained control over what shows up where\n- **Auto-fill song info** — looks up sequence titles online to populate display name + artist automatically (no more \"JinglePopXmas2019_v3.fseq\" shown to viewers)\n- **GPS proximity check** — separate from the audio gate; restricts who can vote/queue based on their physical location\n- **Configurable request limits** — per-viewer cap on jukebox requests per session (1-20)\n\n### Self-hosted, owned, free\n\n- **No cloud dependency** — runs on a Pi, a NAS, a VM, anywhere with Node.js\n- **SQLite database** — single file, easy backup, no separate database server\n- **Open source** — MIT-licensed, hackable, no vendor lock-in\n- **No telemetry** — your data stays on your hardware\n\n---\n\n## ⚠️ Important: HTTPS is required for geolocation features\n\nThe viewer page uses browser geolocation APIs for the **GPS audio gate** and **GPS proximity check**. **Browsers refuse to expose location data on insecure (`http://`) origins** — this is a hardcoded security restriction, not something ShowPilot controls.\n\nIf you plan to use any location-based feature, you **must** serve ShowPilot over HTTPS. Options:\n\n- **Nginx Proxy Manager** (easiest) with a Let's Encrypt cert — point it at ShowPilot on port 3100\n- **Caddy** with automatic HTTPS — single-line reverse proxy config\n- **Cloudflare Tunnel** — free TLS without opening ports\n- **Standalone reverse proxy** (Nginx/Apache) with your own cert\n\nLocalhost (`http://localhost:3100` or `http://127.0.0.1:3100`) is also exempt from this restriction, so local development works without HTTPS. But anything visitors hit needs a cert.\n\nIf you don't use any location features, plain HTTP is fine.\n\n---\n\n## Quick links\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Install on Linux (Debian/Ubuntu/Raspberry Pi OS)](#install--linux-debian--ubuntu--raspberry-pi-os)\n- [Install on Linux (RHEL/Fedora/Rocky/Alma)](#install--linux-rhel--fedora--rocky--alma)\n- [Install on macOS](#install--macos)\n- [Install on Windows](#install--windows)\n- [Install with Docker](#install--docker)\n- [First-run setup](#first-run-setup)\n- [Install the FPP plugin](#install-the-fpp-plugin)\n- [Configuration reference](#configuration-reference)\n- [Running as a service](#running-as-a-service)\n- [Updating](#updating)\n- [Backups](#backups)\n- [Troubleshooting](#troubleshooting)\n\n---\n\n## Requirements\n\n| Component | Minimum | Recommended |\n|-----------|---------|-------------|\n| Node.js   | 18.x    | 20.x or 22.x LTS |\n| RAM       | 256 MB  | 512 MB+ |\n| Disk      | 100 MB for app + your data | 1 GB+ if storing many cover art images |\n| OS        | any modern Linux, macOS 11+, Windows 10+ | Linux for production |\n| FPP       | 7.0+ on a separate device (Pi, BeagleBone, etc.) | latest stable |\n\n**Network:** ShowPilot listens on TCP port 3100 by default. The FPP plugin needs to reach this port. Visitors hit the same port (or whatever you front it with).\n\n---\n\n## Install — Linux (Debian / Ubuntu / Raspberry Pi OS)\n\nThese instructions cover Debian 11+, Ubuntu 22.04+, Raspberry Pi OS Bookworm+. The exact same commands work on a Raspberry Pi 4/5 if you want to colocate ShowPilot with FPP on a single Pi (4GB+ RAM recommended).\n\n### 1. Install Node.js 20 LTS\n\nThe Node.js version in your distro repos is usually too old. Use the official NodeSource installer:\n\n```bash\ncurl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -\nsudo apt-get install -y nodejs build-essential\n```\n\nVerify:\n\n```bash\nnode --version    # should print v20.x.x or higher\nnpm --version\n```\n\n### 2. Install ShowPilot\n\n```bash\n# Pick a location. /opt is conventional for self-hosted apps.\nsudo mkdir -p /opt/showpilot\nsudo chown $USER:$USER /opt/showpilot\ncd /opt/showpilot\n\n# Download the latest release tarball\nwget https://github.com/ShowPilotFPP/ShowPilot/releases/latest/download/showpilot.tar.gz\ntar -xzf showpilot.tar.gz --strip-components=1\nrm showpilot.tar.gz\n\n# Or clone via git if you prefer:\n# git clone https://github.com/ShowPilotFPP/ShowPilot.git .\n\n# Install Node dependencies\nnpm install --omit=dev\n```\n\n### 3. (Optional) Customize the config\n\nShowPilot works out of the box with no configuration — secrets are auto-generated on first run and persisted to `data/secrets.json`. If you want to tweak ports, paths, or other settings:\n\n```bash\ncp config.example.js config.js\nnano config.js\n```\n\nThe most useful setting to think about is `trustProxy`:\n- **Direct exposure (port forward, no proxy):** keep `trustProxy: false` (the default)\n- **Behind a reverse proxy (Nginx Proxy Manager, Caddy, Cloudflare Tunnel, etc.):** set `trustProxy: 1`\n\nFor environments where you'd rather inject secrets at runtime (Kubernetes, Docker secrets, etc.), set the `SHOWPILOT_JWT_SECRET` and `SHOWPILOT_SHOW_TOKEN` environment variables — they take precedence over both `config.js` and auto-generation.\n\n### 4. Start it up\n\n```bash\nnpm start\n```\n\nOn the very first run, you'll see a one-time announcement with your auto-generated **show token** — that's the value you'll paste into the FPP plugin config. You can also retrieve it anytime in the admin UI under **Settings → Plugin → Show Token**.\n\nYou should see `ShowPilot listening on http://0.0.0.0:3100`. Open `http://\u003cyour-server-ip\u003e:3100/admin` in a browser.\n\nDefault login: **`admin` / `admin`** — you'll be forced to change the password on first login.\n\nFor production, see [Running as a service](#running-as-a-service) below to keep ShowPilot running on boot.\n\n---\n\n## Install — Linux (RHEL / Fedora / Rocky / Alma)\n\n### 1. Install Node.js 20 LTS\n\n```bash\ncurl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -\nsudo dnf install -y nodejs gcc-c++ make\n```\n\nVerify:\n\n```bash\nnode --version\nnpm --version\n```\n\n### 2. Install ShowPilot\n\n```bash\nsudo mkdir -p /opt/showpilot\nsudo chown $USER:$USER /opt/showpilot\ncd /opt/showpilot\n\ncurl -L https://github.com/ShowPilotFPP/ShowPilot/releases/latest/download/showpilot.tar.gz \\\n     -o showpilot.tar.gz\ntar -xzf showpilot.tar.gz --strip-components=1\nrm showpilot.tar.gz\n\nnpm install --omit=dev\n```\n\n### 3. Configure \u0026 run\n\nSame as Debian/Ubuntu (sections 3 and 4 above).\n\nIf firewalld is enabled, you'll need to open port 3100:\n\n```bash\nsudo firewall-cmd --permanent --add-port=3100/tcp\nsudo firewall-cmd --reload\n```\n\n---\n\n## Install — macOS\n\nUseful for development and testing on a Mac mini or laptop. Production typically runs on a Pi or VPS, but macOS works fine.\n\n### 1. Install Node.js\n\nThe easiest path is [Homebrew](https://brew.sh):\n\n```bash\nbrew install node@20\n```\n\nOr download the official installer from [nodejs.org](https://nodejs.org/en/download).\n\n### 2. Install ShowPilot\n\n```bash\nmkdir -p ~/showpilot\ncd ~/showpilot\n\ncurl -L https://github.com/ShowPilotFPP/ShowPilot/releases/latest/download/showpilot.tar.gz \\\n     -o showpilot.tar.gz\ntar -xzf showpilot.tar.gz --strip-components=1\nrm showpilot.tar.gz\n\nnpm install --omit=dev\n```\n\n### 3. Run it\n\n```bash\nnpm start\n```\n\nSecrets auto-generate on first run. Optional: copy `config.example.js` to `config.js` if you want to customize ports, paths, or `trustProxy`.\n\nOpen `http://localhost:3100/admin`. Default login `admin` / `admin`.\n\nTo run as a background service, use `launchd` — see [Running as a service](#running-as-a-service) below.\n\n---\n\n## Install — Windows\n\nTested on Windows 10 and 11.\n\n### 1. Install Node.js\n\nDownload the **LTS** installer from [nodejs.org](https://nodejs.org/en/download) and run it. Accept defaults — make sure \"Automatically install the necessary tools\" is checked (it installs build tools needed by `better-sqlite3`).\n\nOpen PowerShell and verify:\n\n```powershell\nnode --version\nnpm --version\n```\n\n### 2. Install ShowPilot\n\nPick a folder (e.g. `C:\\ShowPilot`):\n\n```powershell\nNew-Item -ItemType Directory -Force -Path C:\\ShowPilot\nSet-Location C:\\ShowPilot\n\n# Download the latest release\nInvoke-WebRequest -Uri https://github.com/ShowPilotFPP/ShowPilot/releases/latest/download/showpilot.tar.gz -OutFile showpilot.tar.gz\n\n# Extract (Windows 10 1803+ has tar built in)\ntar -xzf showpilot.tar.gz --strip-components=1\nRemove-Item showpilot.tar.gz\n\nnpm install --omit=dev\n```\n\n### 3. Start it\n\n```powershell\nnpm start\n```\n\nSecrets auto-generate on first run. Optional: `Copy-Item config.example.js config.js` if you want to customize ports, paths, or `trustProxy`.\n\nOpen `http://localhost:3100/admin`. Default login `admin` / `admin`.\n\nIf Windows Firewall prompts you, allow the Node.js process to communicate. To run as a Windows service, use [NSSM](https://nssm.cc/) — see [Running as a service](#running-as-a-service).\n\n---\n\n## Install — Docker\n\nMulti-architecture images (amd64 + arm64) are published to GitHub Container Registry. Pull, configure, run — no build step required.\n\n**Image:** `ghcr.io/showpilotfpp/showpilot:latest`\n**Tags:** [browse all available tags](https://github.com/ShowPilotFPP/ShowPilot/pkgs/container/showpilot)\n\n```bash\n# Make a working directory\nmkdir showpilot \u0026\u0026 cd showpilot\n\n# Pull the image (this is what `docker compose up` will do automatically,\n# but pulling explicitly first lets you confirm connectivity to GHCR)\ndocker pull ghcr.io/showpilotfpp/showpilot:latest\n\n# Set up data directory (config.js is OPTIONAL — see below)\nmkdir showpilot-data\n\n# Download the compose file\ncurl -O https://raw.githubusercontent.com/ShowPilotFPP/ShowPilot/main/docker-compose.yml.example\nmv docker-compose.yml.example docker-compose.yml\n# Edit if you need to change the port mapping\nnano docker-compose.yml\n\n# Start it\ndocker compose up -d\n\n# Watch the logs as it boots — your auto-generated show token will be\n# printed here on first run (you'll need it to configure the FPP plugin).\ndocker compose logs -f\n```\n\nThen open `http://\u003cyour-host\u003e:3100/admin` and continue with [First-run setup](#first-run-setup).\n\n**Optional: customize config.** ShowPilot works out of the box with default settings + auto-generated secrets. If you want to change ports, paths, or `trustProxy`:\n\n```bash\nmkdir showpilot-config\ncurl -O https://raw.githubusercontent.com/ShowPilotFPP/ShowPilot/main/config.example.js\nmv config.example.js showpilot-config/config.js\nnano showpilot-config/config.js\n# Then uncomment the config volume in docker-compose.yml\n```\n\nFor Docker secrets / Kubernetes environments, you can inject `SHOWPILOT_JWT_SECRET` and `SHOWPILOT_SHOW_TOKEN` as environment variables and skip both `config.js` and the auto-generated secrets file entirely.\n\n**Notes for Docker users:**\n\n- The container runs as a non-root `node` user (UID 1000). If you bind-mount the data directory, make sure your host directory is writable by UID 1000 — `chown -R 1000:1000 showpilot-data` if needed.\n- The data volume holds the SQLite database (`showpilot.db`) and cover-art uploads (`covers/`). Back this up regularly.\n- For HTTPS, put the container behind your existing reverse proxy (Nginx Proxy Manager, Traefik, Caddy). HTTPS termination at the proxy is the supported pattern — no built-in TLS in the container.\n- Updating: `docker compose pull \u0026\u0026 docker compose up -d`. Schema migrations run automatically on container start.\n- Pin to a specific version by editing `image:` in `docker-compose.yml` from `:latest` to a specific tag like `:0.18.5`. See available tags at [ghcr.io/ShowPilotFPP/ShowPilot](https://github.com/ShowPilotFPP/ShowPilot/pkgs/container/showpilot).\n- Want to build the image yourself instead of pulling? See the alternative `build:` block in `docker-compose.yml.example`.\n\n---\n\n## First-run setup\n\n1. Open `http://\u003cyour-server-ip\u003e:3100/admin`\n2. Log in with `admin` / `admin`\n3. **Change the default password** (you'll be prompted)\n4. Go to **Plugin** tab → copy the **Show Token** (you'll paste this into FPP)\n5. Optionally go to **Users** tab and add accounts for anyone else who needs admin access\n6. Go to **Settings** tab → review jukebox/voting safeguards and configure **External Audio Access** if you want listeners outside your network to be able to hear the show\n7. Configure your viewer page on the **Viewer Page** tab (use the default ShowPilot template or import the example template provided)\n\n---\n\n## Install the FPP plugin\n\nThe FPP plugin is what reports playback to ShowPilot, hands off requested sequences, and serves audio to viewers.\n\n1. SSH into your FPP device (or open the FPP web UI's shell)\n2. In FPP web UI, go to **Content Setup → Plugin Manager**\n3. Click **Manual Install** (or follow the github URL flow)\n4. Use the ShowPilot plugin URL: `https://github.com/ShowPilotFPP/ShowPilot-plugin`\n5. After install, click **Configure** on the plugin in the plugin list\n6. Fill in:\n   - **ShowPilot URL**: `http://\u003cyour-showpilot-server-ip\u003e:3100`\n   - **Show token**: paste the token you copied from ShowPilot's Plugin tab\n   - **Remote playlist**: the FPP playlist that contains your show sequences\n   - **Interrupt schedule**: enable if you want viewer requests to interrupt the schedule\n7. Click **Save**, then **Restart Listener**\n8. Back in ShowPilot → **Plugin** tab, you should see the plugin go online (green dot in header) within ~30 seconds\n\nIf it doesn't connect, check the plugin log via FPP UI → Status → Logs → `showpilot_listener`.\n\n---\n\n## Configuration reference\n\n`config.js` (created from `config.example.js`):\n\n| Key | Default | Notes |\n|-----|---------|-------|\n| `port` | `3100` | TCP port to listen on |\n| `host` | `0.0.0.0` | Bind address. Use `127.0.0.1` to restrict to localhost only |\n| `dbPath` | `./data/showpilot.db` | SQLite DB path. Created automatically. |\n| `jwtSecret` | _CHANGE_ME_ | Used to sign session cookies. **Must be set to a random value.** |\n| `sessionCookieName` | `showpilot_session` | Browser cookie name |\n| `sessionDurationHours` | `720` (30 days) | Default session length when \"remember me\" is off; remember-me always extends to 30d |\n| `showToken` | _CHANGE_ME_ | Shared secret between ShowPilot and FPP plugin |\n| `viewer.activeWindowSeconds` | `30` | How recently a viewer must have heartbeat'd to count as \"active\" |\n| `viewer.pollIntervalMs` | `5000` | Viewer page state poll fallback (when socket disconnects) |\n| `logLevel` | `info` | `debug` / `info` / `warn` / `error` |\n\nMost operational settings (jukebox depth, vote rules, viewer-page HTML, theme, snow effect, etc.) live in the **admin panel UI**, not in `config.js`.\n\n---\n\n## Running as a service\n\n### Linux — systemd (recommended)\n\nCreate `/etc/systemd/system/showpilot.service`:\n\n```ini\n[Unit]\nDescription=ShowPilot\nAfter=network.target\n\n[Service]\nType=simple\nUser=showpilot\nWorkingDirectory=/opt/showpilot\nExecStart=/usr/bin/node server.js\nRestart=always\nRestartSec=5\nStandardOutput=journal\nStandardError=journal\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=multi-user.target\n```\n\n\u003e **Note:** `Restart=always` is required (not `Restart=on-failure`). ShowPilot's in-app updater exits cleanly (code 0) after downloading an update so the new code is picked up on restart — `on-failure` won't restart on a clean exit, leaving ShowPilot stopped after an update. If you have an existing install with `Restart=on-failure`, fix it with:\n\u003e ```bash\n\u003e sudo sed -i 's/Restart=on-failure/Restart=always/' /etc/systemd/system/showpilot.service\n\u003e sudo systemctl daemon-reload\n\u003e ```\n\nThen:\n\n```bash\n# Create the service user\nsudo useradd -r -s /bin/false -d /opt/showpilot showpilot\nsudo chown -R showpilot:showpilot /opt/showpilot\n\nsudo systemctl daemon-reload\nsudo systemctl enable --now showpilot\nsudo systemctl status showpilot\n\n# View logs\nsudo journalctl -u showpilot -f\n```\n\n### Linux — pm2 (alternative)\n\n```bash\nsudo npm install -g pm2\ncd /opt/showpilot\npm2 start server.js --name showpilot\npm2 startup    # follow the printed instructions\npm2 save\n```\n\n### macOS — launchd\n\nCreate `~/Library/LaunchAgents/com.showpilot.plist`:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n\u003cdict\u003e\n  \u003ckey\u003eLabel\u003c/key\u003e\n  \u003cstring\u003ecom.showpilot\u003c/string\u003e\n  \u003ckey\u003eProgramArguments\u003c/key\u003e\n  \u003carray\u003e\n    \u003cstring\u003e/usr/local/bin/node\u003c/string\u003e\n    \u003cstring\u003e/Users/YOURNAME/showpilot/server.js\u003c/string\u003e\n  \u003c/array\u003e\n  \u003ckey\u003eWorkingDirectory\u003c/key\u003e\n  \u003cstring\u003e/Users/YOURNAME/showpilot\u003c/string\u003e\n  \u003ckey\u003eRunAtLoad\u003c/key\u003e\n  \u003ctrue/\u003e\n  \u003ckey\u003eKeepAlive\u003c/key\u003e\n  \u003ctrue/\u003e\n  \u003ckey\u003eStandardOutPath\u003c/key\u003e\n  \u003cstring\u003e/Users/YOURNAME/showpilot/showpilot.log\u003c/string\u003e\n  \u003ckey\u003eStandardErrorPath\u003c/key\u003e\n  \u003cstring\u003e/Users/YOURNAME/showpilot/showpilot.log\u003c/string\u003e\n\u003c/dict\u003e\n\u003c/plist\u003e\n```\n\nReplace `YOURNAME` and the `node` path (find with `which node`). Then:\n\n```bash\nlaunchctl load ~/Library/LaunchAgents/com.showpilot.plist\n```\n\n### Windows — NSSM\n\n[NSSM](https://nssm.cc/download) wraps any program as a Windows service.\n\n```powershell\n# Download and extract NSSM, then:\n.\\nssm.exe install ShowPilot\n```\n\nIn the GUI that opens:\n- **Path:** `C:\\Program Files\\nodejs\\node.exe`\n- **Startup directory:** `C:\\ShowPilot`\n- **Arguments:** `server.js`\n\nClick **Install service**, then start it:\n\n```powershell\nnssm start ShowPilot\n# Or in services.msc, find \"ShowPilot\" and start it\n```\n\n---\n\n## Updating\n\n### From a release tarball\n\n```bash\ncd /opt/showpilot\nsudo systemctl stop showpilot    # or pm2 stop showpilot\n\n# Backup first\ncp -r data data.backup-$(date +%F)\n\n# Get the new version\nwget -O showpilot.tar.gz https://github.com/ShowPilotFPP/ShowPilot/releases/latest/download/showpilot.tar.gz\ntar -xzf showpilot.tar.gz --strip-components=1\nrm showpilot.tar.gz\nnpm install --omit=dev\n\nsudo systemctl start showpilot\n```\n\nDatabase migrations run automatically on startup. Your config and data are preserved.\n\n### From git\n\n```bash\ncd /opt/showpilot\ngit pull\nnpm install --omit=dev\nsudo systemctl restart showpilot\n```\n\n---\n\n## Backups\n\nThe whole application state lives in two places:\n- `config.js` — your secrets and bind config\n- `data/` directory — SQLite database, cover art images, viewer page templates\n\nBack both up:\n\n```bash\n# Full backup\ntar -czf showpilot-backup-$(date +%F).tar.gz config.js data/\n```\n\nRestore is just extracting the backup back into the install directory.\n\nTo dump just the SQLite DB for inspection or migration:\n\n```bash\nsqlite3 data/showpilot.db .dump \u003e showpilot.sql\n```\n\n---\n\n## Troubleshooting\n\n### \"Cannot connect to FPP plugin\" / plugin shows offline\n\n- Verify the `showToken` in `config.js` exactly matches what you entered in the FPP plugin config\n- Check FPP can reach ShowPilot: `curl http://\u003cshowpilot-ip\u003e:3100/api/plugin/state -H \"remotetoken: YOUR_TOKEN\"`\n- Check the plugin log on FPP: web UI → **Status → Logs → showpilot_listener**\n- Restart the plugin listener via the FPP web UI\n\n### \"Audio doesn't play for cellular listeners\"\n\nShowPilot needs to be reachable from the public internet for off-network audio. Either:\n- Set up a reverse proxy with a public domain, then enter that domain in **Settings → External Audio Access**\n- Use [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) for a domain without exposing your home IP\n\n### \"I forgot my admin password\"\n\nReset directly in the database:\n\n```bash\ncd /opt/showpilot\nsqlite3 data/showpilot.db \"DELETE FROM users WHERE username='admin';\"\n# Then restart ShowPilot — it'll re-seed the default admin/admin user.\n```\n\nIf you have a working admin account, just use the **Users** tab → **Reset PW** for any other user.\n\n### \"Port 3100 already in use\"\n\nEdit `config.js`, change `port` to something free (e.g. `3101`), restart.\n\n### \"permission denied\" on `/opt/showpilot`\n\nThe service user (`showpilot` if following systemd setup) needs write access to `data/` for SQLite:\n\n```bash\nsudo chown -R showpilot:showpilot /opt/showpilot/data\n```\n\n### \"Cover art doesn't show\" / \"wrong covers\"\n\nIn admin → **Sequences**, click **Fetch Covers** to re-pull all sequence covers from iTunes. If a specific cover is wrong, click on it directly to upload or replace.\n\n### Logs\n\n```bash\n# systemd\nsudo journalctl -u showpilot -f --since \"10 minutes ago\"\n\n# pm2\npm2 logs showpilot\n```\n\n---\n\n## Project structure (for the curious)\n\n```\nshowpilot/\n├── server.js                # Express app + Socket.io server\n├── config.js                # Your config (gitignored)\n├── config.example.js        # Template config\n├── package.json\n├── lib/\n│   ├── db.js                # SQLite schema, migrations, helpers\n│   ├── viewer-renderer.js   # Server-side template rendering for the viewer page\n│   ├── cover-art.js         # iTunes cover lookup, cache-busting\n│   └── ...\n├── routes/\n│   ├── admin.js             # /api/admin/* endpoints\n│   ├── viewer.js            # /api/viewer/* + audio streaming\n│   └── plugin.js            # /api/plugin/* (FPP plugin talks here)\n├── public/\n│   ├── admin/               # Admin SPA\n│   ├── viewer.html          # Default viewer page template\n│   └── rf-compat.js         # Viewer-side audio player + visual effects\n└── data/                    # SQLite + cover art (gitignored)\n```\n\n---\n\n## License\n\nMIT. Use it however you like — just don't blame me if your show breaks on Halloween night.\n\n## Contributing\n\nIssues and PRs welcome at https://github.com/ShowPilotFPP/ShowPilot\n\nIf you have ideas, find bugs, or want to share what your show looks like running on ShowPilot — please post in the xLights forum or open a GitHub issue.\n\n---\n\n**Have fun, and Merry Christmas / Happy Halloween / etc!** 🎄🎃🎆\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshowpilotfpp%2Fshowpilot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshowpilotfpp%2Fshowpilot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshowpilotfpp%2Fshowpilot/lists"}