A Python implementation of the osu! lazer server backend.
-
REST API (
/api/v2/) - Compatible with osu! lazer client- User authentication (OAuth2 with JWT tokens)
- User profiles and statistics (all game modes)
- Beatmap and beatmapset endpoints
- Score submission and retrieval
- Multiplayer room management
- Friends and blocks (with database persistence)
- Chat channels and messaging
- Notifications with WebSocket support
- Seasonal backgrounds
-
Real-time Hubs (ASP.NET Core SignalR protocol)
/spectator- Live gameplay spectating and frame data/multiplayer- Real-time multiplayer room coordination/metadata- User presence tracking and online status- MessagePack binary serialization support
- Variable-length integer (VarInt) message framing
- Python 3.11+
- SQLite (default) or PostgreSQL
- uv (recommended) or pip
# Clone or navigate to the repository
cd py_lazer_server
# Using uv (recommended)
uv sync
# Or using pip
python -m venv .venv
source .venv/bin/activate # Linux/macOS
pip install -e ".[dev]"The server uses environment variables or a .env file:
# Server
DEBUG=true
HOST=0.0.0.0
PORT=8000
# Database
DATABASE_URL=sqlite+aiosqlite:///./osu.db
# or for PostgreSQL:
# DATABASE_URL=postgresql+asyncpg://user:pass@localhost/osu
# Security
SECRET_KEY=your-secret-key-here
# OAuth2 Client (must match osu! client configuration)
OAUTH_CLIENT_ID=5
OAUTH_CLIENT_SECRET=change-me# Using uv
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000
# Or using python directly
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadThe server will be available at:
- API:
http://localhost:8000/api/v2/ - SignalR hubs:
http://localhost:8000/spectator,/multiplayer,/metadata - API docs:
http://localhost:8000/docs
To connect the osu! lazer client to this server:
- Modify
osu.Game/Online/LocalEndpointConfiguration.cs:
public class LocalEndpointConfiguration : EndpointConfiguration
{
public LocalEndpointConfiguration()
{
WebsiteUrl = APIUrl = @"http://localhost:8000";
APIClientSecret = @"change-me";
APIClientID = "5";
SpectatorUrl = "http://localhost:8000/spectator";
MultiplayerUrl = "http://localhost:8000/multiplayer";
MetadataUrl = "http://localhost:8000/metadata";
}
}- Update
OsuGameBase.csto useLocalEndpointConfiguration:
public virtual EndpointConfiguration CreateEndpoints() => new LocalEndpointConfiguration();-
For HTTP (non-HTTPS) connections, bypass SSL in
osu-framework:- Add SSL bypass to
SocketsHttpHandlerinWebRequest.cs - Set environment variable:
OSU_INSECURE_REQUESTS=1
- Add SSL bypass to
-
Build and run the client:
export OSU_INSECURE_REQUESTS=1
dotnet build osu.Desktop.slnf
dotnet run --project osu.DesktopPOST /oauth/token- Get access token (username/password grant)
GET /api/v2/me- Current user profileGET /api/v2/me/{mode}- Current user with mode-specific stats
GET /api/v2/users/{id}- Get user by IDGET /api/v2/users/{id}/{mode}- Get user with mode-specific statsGET /api/v2/users/lookup- Lookup user by ID or username
GET /api/v2/friends- List friendsPOST /api/v2/friends- Add friendDELETE /api/v2/friends/{target_id}- Remove friendGET /api/v2/blocks- List blocked usersPOST /api/v2/blocks- Block userDELETE /api/v2/blocks/{target_id}- Unblock user
GET /api/v2/chat/channels- List chat channelsGET /api/v2/chat/updates- Get chat updates (polling)POST /api/v2/chat/ack- Acknowledge messages
GET /api/v2/notifications- Get notifications (includes WebSocket endpoint)POST /api/v2/notifications/mark-read- Mark as read- WebSocket:
/api/v2/notifications/websocket- Real-time notifications
GET /api/v2/beatmaps/{id}- Get beatmapGET /api/v2/beatmaps/lookup- Lookup by checksum/filename/idGET /api/v2/beatmapsets/{id}- Get beatmapsetGET /api/v2/beatmapsets/search- Search beatmapsets
POST /api/v2/beatmaps/{id}/solo/scores- Request score tokenPUT /api/v2/beatmaps/{id}/solo/scores/{token}- Submit scoreGET /api/v2/beatmaps/{id}/scores- Get beatmap scoresGET /api/v2/users/{id}/scores/{type}- Get user scores (best/recent/firsts)
GET /api/v2/rooms- List roomsPOST /api/v2/rooms- Create roomGET /api/v2/rooms/{id}- Get room detailsPUT /api/v2/rooms/{id}/users/{user_id}- Join roomDELETE /api/v2/rooms/{id}/users/{user_id}- Leave room
GET /api/v2/seasonal-backgrounds- Seasonal background images
The server implements ASP.NET Core SignalR protocol for real-time communication:
BeginPlaySession- Start spectating sessionEndPlaySession- End spectating sessionSendFrameData- Send gameplay frame dataStartWatchingUser/EndWatchingUser- Watch/unwatch players
- Room creation, joining, and state synchronization
- Playlist management
- Match start/end coordination
BeginWatchingUserPresence- Subscribe to online usersEndWatchingUserPresence- UnsubscribeUpdateActivity- Update user activityUpdateStatus- Update online statusUserPresenceUpdated- Broadcasts presence changes
py_lazer_server/
├── app/
│ ├── api/
│ │ ├── v2/ # REST API endpoints
│ │ │ ├── oauth.py
│ │ │ ├── me.py
│ │ │ ├── users.py
│ │ │ ├── beatmaps.py
│ │ │ ├── scores.py
│ │ │ ├── rooms.py
│ │ │ ├── friends.py
│ │ │ ├── blocks.py
│ │ │ ├── chat.py
│ │ │ └── notifications.py
│ │ ├── signalr.py # SignalR hub implementations
│ │ └── deps.py # Dependency injection
│ ├── core/ # Configuration and utilities
│ │ ├── config.py
│ │ ├── database.py
│ │ └── security.py
│ ├── models/ # SQLAlchemy models
│ │ ├── user.py # User, UserStatistics, UserRelation
│ │ ├── beatmap.py
│ │ ├── score.py
│ │ └── multiplayer.py
│ └── main.py # Application entry point
├── tests/
├── pyproject.toml
└── README.md
- User - User accounts with profile information
- UserStatistics - Per-mode statistics (pp, rank, play count, etc.)
- UserRelation - Friends and blocks relationships
- Beatmap / BeatmapSet - Beatmap metadata
- Score / ScoreToken - Score submissions
- MultiplayerRoom / MultiplayerPlaylistItem - Multiplayer state
MIT License - See LICENSE file for details.
This implementation is based on the official osu! server infrastructure:
- osu-web - REST API reference
- osu-server-spectator - Real-time hub reference
- osu - Client implementation reference