| .agent | ||
| .cursor | ||
| .github/workflows | ||
| docs | ||
| packages | ||
| public | ||
| screenshots | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .prettierrc | ||
| Dockerfile | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.en.md | ||
| README.md | ||
Music Together
A real-time collaborative music listening platform — create a room, invite friends, and listen to the same song perfectly synchronized.
Screenshots
Desktop
| Home | Search | Player | Chat |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Mobile
| Home | Search | Player | Chat |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Lyrics Display Comparison
| Desktop Lyrics | Portrait Default (Cover) | Portrait Lyrics Mode |
|---|---|---|
![]() |
![]() |
![]() |
Features
- Real-time sync -- NTP clock synchronization + scheduled execution for minimal latency
- Multi-platform music sources -- NetEase Cloud Music, QQ Music
- Apple Music-style lyrics -- Word-by-word animated lyrics, responsive on desktop and mobile
- VIP song support -- Room-scoped cookie pool via NetEase QR login
- RBAC permissions -- Host > Admin > Member with fine-grained access control
- Voting system -- Members vote to control playback actions
- Play modes -- Sequential, single loop, list loop, shuffle
- Real-time chat -- In-room text messaging with system messages
- Role grace period -- Privileged users retain roles for 30s after disconnect
- Mobile responsive -- Adaptive layout with orientation-based switching
Quick Start
Prerequisites
- Node.js >= 22
- pnpm >= 10
Install & Develop
git clone https://github.com/Yueby/music-together.git
cd music-together
pnpm install
pnpm dev
Frontend: http://localhost:5173 | Backend: http://localhost:3001
Deploy
Single-image Docker deployment:
docker run -d --name music-together --restart unless-stopped \
-p 3001:3001 \
ghcr.io/yueby/music-together:latest
If host port
3001is already in use, change the left side of-p <host-port>:<container-port>, for example-p 8080:3001.
In default auto mode, the frontend connects back to the current origin automatically; the server allows all origins and decides whether to set the cookie Secure flag based on the incoming request protocol.
Set CLIENT_URL only when you need an explicit origin whitelist:
docker run -d --name music-together --restart unless-stopped \
-p 3001:3001 \
-e CLIENT_URL=https://music.example.com \
ghcr.io/yueby/music-together:latest
CLIENT_URLis mainly for explicit whitelist mode or separated frontend/backend deployments. In default auto mode, you usually do not need to set it manually.If you expose HTTPS through Nginx / Caddy / 1Panel / Lucky, make sure the proxy forwards
X-Forwarded-Proto, or the server cannot auto-detect whether it should issue Secure cookies.
Push to main triggers GitHub Actions to build and push the image. See Architecture Docs for details.
Project Structure
packages/
client/ -- Frontend React application
server/ -- Backend Node.js service
shared/ -- Shared types, constants, and permission definitions
Acknowledgements
| Library | Description |
|---|---|
| Howler.js | Web audio playback |
| Apple Music-like Lyrics | Lyrics component (GPL-3.0) |
| Meting | Multi-platform music API |
| NeteaseCloudMusicApi Enhanced | NetEase Cloud Music API |
| CASL | Permission management |
| Zustand | State management |
| shadcn/ui | UI component library |
| Motion | Animation library |








