Bri-Tunes/README.md

141 lines
4.9 KiB
Markdown

# Tunes
A self-contained music website: browse and listen to songs and playlists,
with user accounts and an admin upload UI. Everything runs from a single
Node.js process with an embedded SQLite database and local media storage —
no external services required.
## Features (v1)
- **Public browse & listen**
- Home page with featured playlists and recently added songs
- Paginated, searchable song list (title / artist / album)
- Playlist grid and detail view with "Play all"
- Persistent bottom-of-page audio player with queue support
- HTTP Range streaming, so seeking/scrubbing works correctly
- **User accounts**
- Email + password registration (argon2id hashing)
- Login / logout with SQLite-backed sessions (survive restarts)
- Account page: update display name, change password
- CSRF protection on all state-changing routes
- **Admin**
- Upload songs with cover art; title/artist/album/genre/year metadata
- Duration auto-extracted from the audio file
- Create and edit playlists, add/remove tracks
- Toggle songs and playlists between public and private
- First user who registers with `ADMIN_BOOTSTRAP_EMAIL` is auto-promoted
to admin (only while no admin exists yet)
## Roadmap (not in v1)
- Generate new music via an external API from within the app
- Let logged-in users publish their own songs and create playlists
- Tune into streaming radio stations
## Tech stack
- **Node.js + Express 4** — server and routing
- **SQLite** via `better-sqlite3` — embedded database, WAL mode
- **EJS** + `express-ejs-layouts` — server-rendered views
- **argon2** — password hashing
- **express-session** + `better-sqlite3-session-store` — persistent sessions
- **multer** — file uploads (audio + cover art)
- **music-metadata** — extract duration from uploaded audio
- **csrf-sync**, **zod**, **pino** — CSRF, validation, logging
- **htmx** (vendored) — small sprinklings of interactivity, no build step
## Getting started
### Prerequisites
- Node.js 18+ (tested on 18.19)
- npm
### Install and run
```bash
git clone <your-repo-url> tunes
cd tunes
npm install
cp .env.example .env
# Edit .env:
# SESSION_SECRET=<a long random string>
# ADMIN_BOOTSTRAP_EMAIL=<your email>
node server.js
```
The server boots at http://localhost:3000 and runs database migrations
automatically against `tunes.db` in the project root.
For auto-reload during development:
```bash
npm run dev
```
### Creating the first admin
1. Open http://localhost:3000/register
2. Register with the email you set as `ADMIN_BOOTSTRAP_EMAIL` in `.env`.
That first matching registration is automatically given the `admin` role.
3. Once logged in, visit `/admin/songs` to upload audio and `/admin/playlists`
to create playlists.
Any subsequent registrations are normal users.
### Adding music
1. Go to `/admin/songs/new`
2. Fill in title, artist, and (optionally) album/genre/year
3. Choose an audio file (mp3, m4a, ogg, flac, wav, opus, webm — up to 100 MB)
4. Optionally add a cover image
5. Check "Public" so visitors can see and play it, then click **Upload**
Uploaded files live under `media/audio/` and `media/covers/`. The database
stores relative paths, so you can move the whole project folder freely as
long as `media/` and `tunes.db` stay together.
## Configuration
All settings come from environment variables (loaded from `.env` via
`dotenv`):
| Variable | Default | Purpose |
| --- | --- | --- |
| `PORT` | `3000` | HTTP port |
| `SESSION_SECRET` | *(insecure default)* | Session cookie signing secret — **set this in production** |
| `ADMIN_BOOTSTRAP_EMAIL` | *(unset)* | Email that auto-becomes admin on first registration |
| `DB_PATH` | `./tunes.db` | SQLite database file |
| `MEDIA_DIR` | `./media` | Root directory for audio and cover uploads |
## Project layout
```
tunes/
├── server.js # entry point: loads env, runs migrations, starts app
├── db/
│ ├── index.js # SQLite connection + migration runner
│ └── migrations/*.sql # schema migrations
├── src/
│ ├── app.js # Express wiring (sessions, CSRF, views, routes)
│ ├── middleware/auth.js # requireUser / requireAdmin
│ ├── routes/
│ │ ├── public.js # /, /songs, /playlists, /stream/:id
│ │ ├── auth.js # /register, /login, /logout
│ │ ├── account.js # /account
│ │ └── admin.js # /admin/songs, /admin/playlists
│ ├── services/ # users, songs, playlists (DB access)
│ └── views/ # EJS templates
├── public/ # static CSS, JS, vendored htmx
└── media/ # runtime audio + cover uploads (git-ignored)
```
## Data and backups
Everything you care about lives in two places:
- `tunes.db` — users, songs, playlists, sessions
- `media/` — audio files and cover art
Back up both together to preserve the full state of the site.