|
|
||
|---|---|---|
| db | ||
| public | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| PWA.md | ||
| README.md | ||
| package-lock.json | ||
| package.json | ||
| server.js | ||
README.md
Tunes
A self-hosted music website: browse and listen to songs and playlists, with user accounts, social features, and AI-assisted music and cover art generation. Everything runs from a single Node.js process with an embedded SQLite database and local media storage — no external services required beyond an optional ComfyUI instance for AI generation.
Features
-
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, repeat, and visualizer
- HTTP Range streaming so seeking/scrubbing works correctly
- PWA-ready with Media Session API: lock-screen controls and background playback on mobile
- Lightbox for cover art
-
User accounts
- Email + password registration (argon2id hashing)
- Optional email verification via SMTP
- Login / logout with SQLite-backed sessions (survive restarts)
- Account page: update display name, avatar, and password
- Public profile pages with song/playlist activity
- CSRF protection on all state-changing routes
-
Social
- Like and favorite songs and playlists
- In-app notifications
- Profile pages showing liked and favorited content
-
User music
- Logged-in users can upload their own songs and create playlists
- Visibility controls:
public,logged_in,vip, orprivate - NSFW flag for explicit content
-
AI music generation (requires ComfyUI)
- Generate songs from style prompts, lyrics, BPM, key, duration, and creativity settings
- Per-user rate limiting (cooldown + hourly cap)
- Generated songs can be previewed, published, or deleted
- Optionally generate album cover art after publishing
-
Admin panel (
/admin)- User management: disable, enable, verify, grant/revoke VIP, delete
- ComfyUI integration settings: base URL, music workflow JSON, image workflow JSON, node ID mappings
- Toggle music generation and image generation on/off site-wide
-
My Music (
/mymusic) — for any logged-in user- Upload songs with cover art; title/artist/album/genre/year/BPM metadata
- Duration auto-extracted from the audio file
- Create and edit playlists, add/remove/reorder tracks
- Bulk visibility changes
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, avatars)
- sharp — server-side image resizing and conversion
- music-metadata — extract duration from uploaded audio
- nodemailer — email verification
- csrf-sync, zod, pino — CSRF, validation, logging
- htmx (vendored) — progressive interactivity, no build step
- CropperJS (vendored) — client-side avatar cropping
Getting started
Prerequisites
- Node.js 18+ (tested on 18.19)
- npm
- (optional) A running ComfyUI instance for AI generation
Install and run
git clone <your-repo-url> tunes
cd tunes
npm install
cp .env.example .env
# Edit .env — at minimum set SESSION_SECRET and ADMIN_BOOTSTRAP_EMAIL
node server.js
The server starts at http://localhost:3000 and runs database migrations
automatically against tunes.db in the project root.
For auto-reload during development:
npm run dev
Creating the first admin
- Open http://localhost:3000/register
- Register with the email you set as
ADMIN_BOOTSTRAP_EMAILin.env. That first matching registration is automatically given theadminrole. - Visit
/adminto manage users and configure generation settings. - Visit
/mymusic/songsto upload audio and/mymusic/playliststo create playlists.
Any subsequent registrations are normal users.
Adding music
- Go to
/mymusic/songs/new - Fill in title, artist, and (optionally) album/genre/year
- Choose an audio file (mp3, m4a, ogg, flac, wav, opus, webm — up to 100 MB)
- Optionally add a cover image
- Set visibility to 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.
AI generation setup
- Stand up a ComfyUI instance accessible from the server.
- In
/admin, set the ComfyUI Base URL (e.g.http://localhost:8188). - Upload a Music Workflow JSON and fill in the node ID mappings for your workflow.
- Optionally upload an Image Workflow JSON and set the prompt node ID for cover art.
- Check Enable Song Generation (and Enable Album Cover Generation if desired).
- VIP users (and admins) can now visit
/generateto produce songs.
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 key — set this in production |
ADMIN_BOOTSTRAP_EMAIL |
(unset) | Email auto-promoted to admin on first registration |
DB_PATH |
./tunes.db |
SQLite database file path |
MEDIA_DIR |
./media |
Root directory for all uploaded and generated files |
SITE_NAME |
Bri-Tunes |
Site name shown in the header and page titles |
APP_BASE_URL |
http://localhost:3000 |
Full URL used in email verification links |
SMTP_HOST |
(unset) | SMTP server hostname (leave blank to print verify URLs to console) |
SMTP_PORT |
587 |
SMTP port |
SMTP_SECURE |
false |
Use TLS (true) or STARTTLS (false) |
SMTP_USER |
(unset) | SMTP username |
SMTP_PASS |
(unset) | SMTP password |
SMTP_FROM |
(unset) | From address for outgoing email |
Project layout
tunes/
├── server.js # entry point: loads env, runs migrations, starts app
├── db/
│ ├── index.js # SQLite connection + migration runner
│ └── migrations/*.sql # numbered schema migrations
├── src/
│ ├── app.js # Express wiring (sessions, CSRF, views, routes)
│ ├── middleware/auth.js # requireUser / requireAdmin / requireVip
│ ├── routes/
│ │ ├── public.js # /, /songs, /playlists, /profiles, /stream/:id
│ │ ├── auth.js # /register, /login, /logout, /verify-email
│ │ ├── account.js # /account — profile and password settings
│ │ ├── admin.js # /mymusic — user song and playlist management
│ │ ├── admin-panel.js # /admin — site administration
│ │ ├── generate.js # /generate — AI music + cover art generation
│ │ └── social.js # /api — likes, favorites
│ ├── services/ # users, songs, playlists, social, generation, settings
│ └── views/ # EJS templates
├── public/
│ ├── css/app.css # main stylesheet
│ └── js/ # player, visualizer, social, lightbox, etc.
└── media/ # runtime uploads and generated files (git-ignored)
Data and backups
Everything you care about lives in two places:
tunes.db— users, songs, playlists, sessions, notifications, generation recordsmedia/— audio files, cover art, avatars, and AI-generated files
Back up both together to preserve the full state of the site.