| Crates.io | frametogether-server |
| lib.rs | frametogether-server |
| version | 0.1.0 |
| created_at | 2025-08-02 02:28:37.140333+00 |
| updated_at | 2025-08-02 02:28:37.140333+00 |
| description | Sync video playback with friends! |
| homepage | |
| repository | https://github.com/un1970ix/frametogether-server |
| max_upload_size | |
| id | 1778066 |
| size | 106,742 |
A lightweight WebSocket server for synchronizing video playback across multiple browsers. Built with Rust for performance and reliability.
This server communicates with the FrameTogether browser extension.
You can self-host FrameTogether to run your own instance, or use the default public instance hosted by the author at frametogether.19702038.xyz. The default instance temporarily stores IP addresses only in RAM for rate limiting and does not persist or share them. The author is not liable for any data handling or security issues on self-hosted or third-party instances.
Current Status: Built specifically for MUBI video synchronization. Future versions may support additional platforms.
FrameTogether is an independent project and is not affiliated with, endorsed by, or connected to MUBI or its affiliates in any way.
Clone the repository:
git clone git@github.com:un1970ix/frametogether-server.git
cd frametogether-server
Start the server:
docker compose up -d
The server will start on port 47642. To use a different port:
PORT=8080 docker compose up -d
Clone the repository:
git clone git@github.com:un1970ix/frametogether-server.git
cd frametogether-server
Requirements:
cargo build --release
./target/release/frametogether-server
Configuration via environment variables:
| Variable | Default | Description |
|---|---|---|
PORT or ADDR |
47642 | Server port or full address. |
MAX_ROOMS |
1000 | Maximum concurrent rooms. |
RATE_LIMIT_PER_SECOND |
30 | Requests per second per IP. |
RUST_LOG |
info | Logging level options are debug, info, warn, or error. |
The server uses WebSocket with JSON messages.
Create Room
{"type": "Create"}
Join Room
{"type": "Join", "room_id": "abc123"}
Update Video State (Host only.)
{"type": "State", "time": 120.5, "paused": false}
Leave Room
{"type": "Leave"}
Heartbeat (Keeps connection alive.)
{"type": "Heartbeat"}
Room Created
{
"type": "RoomCreated",
"room_id": "abc123"
}
Room Joined
{
"type": "RoomJoined",
"room_id": "abc123",
"is_host": true,
"your_name": "Happy Panda",
"participants": []
}
Video Sync (Sent to non-hosts.)
{
"type": "Sync",
"time": 120.5,
"paused": false
}
User Joined
{
"type": "UserJoined",
"user": {"name": "Clever Fox", "is_host": false}
}
User Left
{
"type": "UserLeft",
"user_name": "Clever Fox"
}
Error
{
"type": "Error",
"message": "Room not found"
}
The server maintains all state in memory:
Run with debug logging:
RUST_LOG=debug cargo run
Format code:
cargo fmt
Check for issues:
cargo clippy
The included compose.yml provides a production-ready setup:
/health endpoint.For production, place behind a reverse proxy (Such as nginx or Caddy.) for:
For nginx:
location /sync {
proxy_pass http://localhost:47642;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
See the LICENSE file for details.
Pull requests are welcome. Please run cargo fmt and cargo clippy before submitting.