No description
- JavaScript 86.4%
- CSS 8.2%
- HTML 5.1%
- Dockerfile 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Transient hints like 'saved' now fade away on their own; errors keep staying visible until the user deals with them. A new status cancels the pending timer so a fresh message is never cut short by an old one. |
||
| test | ||
| web | ||
| .env.example | ||
| .gitignore | ||
| db.js | ||
| docker-compose.yml | ||
| Dockerfile | ||
| games.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| server.js | ||
| watch.js | ||
webMVF
Online conference tool like Discord: voice/video rooms with screen share, room chat with media, per-room whiteboards, and watch-Youtube-together. Entry with just a name; optionally register the name (password) and use the admin panel.
Features
- Voice/video rooms - P2P WebRTC mesh (server only relays signaling, never touches media), per-room chat, talking indicator, member list with mic + voice-activity, room list with per-room user counts, create/join rooms.
- Screen share -
getDisplayMedia(full desktop selectable, no tab-only picker), replaces camera while sharing, stops automatically on room change. - Room chat + media - send text plus images/video/audio attachments (uploaded to the server, 25 MB cap, extension whitelist).
- Whiteboard - per room: pen, eraser, color, 3 brush sizes, drop images (drag to move), clear. Persisted per room, shared live.
- Watch together - paste a YouTube URL, the server resolves it with
yt-dlp, transcodes in real time withffmpegto HLS, and all clients in the room follow the same live edge (hls.js). Play / pause / resume / seek / stop are shared room state. - Accounts - register your name with a password (first registered user becomes admin). Registered names must enter their password on join. Passwords are remembered per browser (localStorage).
- Roles + admin panel - manage registered users (role, reset password, delete), set/remove the server-wide password, set/remove per-room passwords. Admins enter all rooms without a password.
- Password-protected rooms - admins set a room password; users can be invited in (invitee bypasses the password).
- Profile pictures - pick an avatar on the landing page (stored per browser), shown in chat, member list and video tiles.
- Device test - modal to pick/test microphone + camera before joining.
- Reconnect - identity (uuid + name) survives page reloads and socket drops.
- Config via
.env- server name, port, DB/HLS/upload/whiteboard paths, STUN/TURN (ICE) servers, yt-dlp/ffmpeg binaries.
Quickstart (local)
npm install
cp .env.example .env # adjust ICE servers etc.
npm start # http://localhost:3000
Requires yt-dlp and ffmpeg on the PATH (for watch together; voice/video,
chat and the whiteboard work without them).
Docker
cp .env.example .env # adjust ICE servers etc.
docker compose up -d --build
- Image: multi-stage
node:22-slim(builds native deps, installs ffmpeg + python3 + ca-certificates + yt-dlp; ca-certificates fixes yt-dlp'sSSL: CERTIFICATE_VERIFY_FAILEDon YouTube). - Data (DB, HLS segments, uploads, whiteboards) persists in
./data(volume/data). - Healthcheck on
/healthz.
Configuration (.env)
| Variable | Default | Meaning |
|---|---|---|
PORT |
3000 |
HTTP port |
SERVER_NAME |
webMVF |
Name shown to clients |
DB_FILE |
data/webmvf.db |
SQLite database (users, roles, room passwords, invites) |
HLS_DIR |
data/hls |
HLS segment storage |
UPLOADS_DIR |
data/uploads |
Chat attachment storage (served at /uploads/) |
WB_DIR |
data/whiteboards |
Per-room whiteboard JSON |
ICE_STUN_URLS |
stun:stun.l.google.com:19302 |
Comma separated STUN urls |
ICE_TURN_URLS |
- | Comma separated TURN urls |
ICE_TURN_USERNAME |
- | TURN username |
ICE_TURN_SECRET |
- | With username: time-based creds (RFC 5389 style), generated per client |
ICE_TURN_CREDENTIAL |
- | Static credential, used when ICE_TURN_SECRET is empty |
ICE_TTL_SEC |
43200 |
Lifetime of generated TURN credentials |
YTDLP_COOKIES |
- | Path to cookies file for yt-dlp (fixes bot-check blocks) |
YTDLP_BIN |
yt-dlp |
yt-dlp binary |
FFMPEG_BIN |
ffmpeg |
ffmpeg binary |
TURN notes: with ICE_TURN_SECRET set, the server issues a temporary
<expiry>:<username> / HMAC-SHA1 credential pair to every client (works with
coturn use-auth-secret). Without it, ICE_TURN_CREDENTIAL is passed through.
Tests
npm install
npm test
test/db.test.js- SQLite storage: users/roles, settings, room passwords, invites, scrypt hash/verify (module test)test/ice.test.js- ICE server building + TURN credentials (module test)test/watch.test.js- watch state machine with fake yt-dlp/ffmpeg (module test)test/e2e.test.js- full server: HTTP + config/upload REST + sockets + rooms- passwords + invites + signaling relay + whiteboard + watch pipeline + HLS serving + traversal guards (e2e)
No network access needed: e2e uses fake yt-dlp/ffmpeg scripts.
Layout
server.js express + socket.io server (signaling, rooms, chat, whiteboard,
accounts/admin, uploads, HLS)
db.js SQLite storage (better-sqlite3): users, roles, settings,
room passwords, invites
watch.js per-room YouTube -> HLS state machine (yt-dlp + ffmpeg)
web/ vanilla JS client (no build step)
js/ezWebRTC.js RTCPeerConnection wrapper (copied from basicwebrtc)
js/hls.min.js vendored hls.js
js/adapter.min.js vendored webrtc-adapter
test/ node:test suites