Synchronized viewing, theater, live streaming, video, long-distance relationship
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Go to file
zijiren233 07ae5d76e2
fix: ci lint
5 months ago
.cargo fix: ci lint 5 months ago
.config refactor: infra 6 months ago
.github fix: ci lint 5 months ago
benches fix: ci lint 5 months ago
helm/synctv fix: ci lint 5 months ago
migrations fix: ci lint 5 months ago
synctv fix: ci lint 5 months ago
synctv-api fix: ci lint 5 months ago
synctv-cluster fix: ci lint 5 months ago
synctv-common fix: ci lint 5 months ago
synctv-core fix: ci lint 5 months ago
synctv-livestream fix: ci lint 5 months ago
synctv-management fix: ci lint 5 months ago
synctv-media-providers fix: ci lint 5 months ago
synctv-proto fix: ci lint 5 months ago
synctv-proxy fix: ci lint 5 months ago
synctv-xiu fix: ci lint 5 months ago
.dockerignore chore: infra 7 months ago
.env.example fix: ci lint 6 months ago
.gitignore fix: ci lint 5 months ago
Cargo.lock fix: ci lint 5 months ago
Cargo.toml fix: ci lint 5 months ago
Dockerfile feat: more test 6 months ago
README.md fix: ci lint 5 months ago
deny.toml fix: ci lint 5 months ago
docker-compose.dev.yml fix:ci lint 5 months ago
docker-compose.yml fix:ci lint 5 months ago
synctv.example.yaml fix: ci lint 5 months ago

README.md

SyncTV - Rust Implementation

A production-grade real-time synchronized video watching platform built in Rust.

Features

  • Real-time Synchronization: Watch videos together with friends in perfect sync
  • Multi-Provider Support: Bilibili, Alist, Emby, and direct URLs
  • Live Streaming: RTMP push/pull with HLS and FLV support
  • Horizontal Scalability: Kubernetes-ready multi-replica deployment
  • High Performance: Built with Rust for maximum efficiency
  • Type Safety: Compile-time guarantees and zero-cost abstractions

Architecture

  • synctv-core: Core business logic library
  • synctv-api: gRPC + HTTP API service
  • synctv-livestream: Live streaming service (RTMP/HLS/FLV)
  • synctv-cluster: Cluster coordination library
  • synctv-xiu: Consolidated streaming library (RTMP/HLS/HTTP-FLV protocols)

Quick Start

Prerequisites

  • Rust 1.75+ (2021 edition)
  • PostgreSQL 14+
  • Redis 7+

1. Start with Docker Compose

Development build from the local source tree:

docker compose -f docker-compose.dev.yml up -d

This variant builds with the local Dockerfile and ships fixed working development defaults for JWT and cluster secrets.

Prebuilt image deployment:

export SYNCTV_JWT_SECRET="your-secure-random-string-at-least-32-chars"
export SYNCTV_SERVER_CLUSTER_SECRET="your-secure-random-cluster-secret"
export SYNCTV_BOOTSTRAP_ROOT_PASSWORD="StrongRootPass12345"
docker compose up -d

This variant uses synctvorg/synctv:v1 from docker-compose.yml and intentionally keeps the environment surface small.

Once the daemon is up, management CLI commands can run inside the container and use the default Unix socket without extra flags:

docker compose exec synctv synctv system stats

2. Manual Environment Variables

export SYNCTV_DATABASE_URL="postgresql://synctv:synctv@localhost:5432/synctv"
export SYNCTV_REDIS_URL="redis://localhost:6379"
export SYNCTV_JWT_SECRET="your-secure-RANDOM-string-WITH-mixed-CASE-123-and-SPECIAL!@#$%"
export SYNCTV_SERVER_CLUSTER_SECRET="your-secure-random-cluster-secret"
export SYNCTV_BOOTSTRAP_CREATE_ROOT_USER=true
export SYNCTV_BOOTSTRAP_ROOT_PASSWORD="StrongRootPass12345"
export SYNCTV_SERVER_PORT=8080
# Validate your configuration before deployment
cargo run --bin synctv -- config validate

# Validate a specific config file
cargo run --bin synctv -- config --config /path/to/synctv.yaml validate

4. Run Database Migrations

# Run embedded migrations with the same config resolution as the server
cargo run --bin synctv -- db migrate

5. Start the Server

# Set JWT secret (required for production, min 32 chars)
export SYNCTV_JWT_SECRET="your-secure-random-string-at-least-32-chars"
export SYNCTV_BOOTSTRAP_ROOT_PASSWORD="StrongRootPass12345"

cargo run --bin synctv -- serve

HTTP/REST and public gRPC share a single API port, defaulting to 0.0.0.0:8080. The management daemon default endpoint is platform-specific:

  • Linux / other Unix: unix://$XDG_STATE_HOME/synctv/run/synctv.sock when XDG_STATE_HOME is set, otherwise unix://$HOME/.local/state/synctv/run/synctv.sock
  • macOS: unix://$HOME/.synctv/run/synctv.sock
  • Windows: http://127.0.0.1:50052

Runtime-owned local files can be relocated with --data-dir, SYNCTV_DATA_DIR, or top-level config data_dir.

data_dir applies to runtime-owned local paths:

  • default management Unix socket path and relative management.unix_socket_path
  • relative logging.file_path
  • relative livestream.hls_storage_path
  • relative cache.proxy_slice_file_cache_dir

data_dir does not rebase static input files:

  • *_file secret references such as jwt.secret_file, management.auth_token_file, oauth2.providers.*.client_secret_file, or provider credential _file fields
  • metrics.tls.cert_path and metrics.tls.key_path

Absolute paths are always used as-is. Relative data_dir from config files is resolved relative to the config file directory; --data-dir and SYNCTV_DATA_DIR are resolved relative to the current working directory.

Secret-like settings can also be loaded from environment file variables, for example SYNCTV_JWT_SECRET_FILE, SYNCTV_MANAGEMENT_AUTH_TOKEN_FILE, SYNCTV_DATABASE_URL_FILE, and SYNCTV_BOOTSTRAP_ROOT_PASSWORD_FILE. Relative env file paths are resolved from the current working directory.

PostgreSQL and Redis can be configured either by URL or by split fields. For PostgreSQL, use database.url / SYNCTV_DATABASE_URL or database.host, database.port, database.username, database.password, database.name with matching SYNCTV_DATABASE_* env vars. For Redis, use redis.url / SYNCTV_REDIS_URL or redis.host, redis.port, redis.username, redis.password, redis.database with matching SYNCTV_REDIS_* env vars. Passwords and URLs support *_file config keys and *_FILE env vars.

On platforms without Unix Domain Socket support, management.transport: unix is rejected during configuration validation instead of silently falling back.

When a Unix socket is not available, the CLI can be pointed at an explicit endpoint with --endpoint or SYNCTV_MANAGEMENT_ENDPOINT, and the server can be configured to listen on TCP at 127.0.0.1:50052. In TCP mode the management listener is always forced to loopback; there is no configurable management host.

6. Remote CLI Operations

All operational CLI commands talk to a running SyncTV server. There is no offline admin mode.

# List users through the local management daemon endpoint
cargo run --bin synctv -- user list

# Inspect effective runtime settings
cargo run --bin synctv -- settings get server

# Update runtime settings through the management daemon
cargo run --bin synctv -- settings update server \
  --set signup_enabled=false \
  --set max_rooms_per_user=42

# Inspect cluster/system stats
cargo run --bin synctv -- system stats

# Inspect or manage remote provider instances
cargo run --bin synctv -- provider list

# List playlists inside a room
cargo run --bin synctv -- playlist list --room-id room-123

# Add a direct media URL into a room playlist
cargo run --bin synctv -- media add-url 'https://cdn.example.com/video.mp4' \
  --room-id room-123 \
  --playlist-id playlist-123

The management daemon executes local CLI requests with built-in god-mode privileges. The compose files and development scripts create a bootstrap administrator automatically; for manual deployments, set SYNCTV_BOOTSTRAP_CREATE_ROOT_USER=true together with a strong SYNCTV_BOOTSTRAP_ROOT_PASSWORD before first startup.

Remote CLI commands may load SyncTV config files to resolve the management endpoint and management bearer token. Explicit CLI flags still take precedence. Endpoint resolution is:

  1. --endpoint
  2. SYNCTV_MANAGEMENT_ENDPOINT
  3. management.* from --config, SYNCTV_CONFIG_PATH, or an auto-discovered config file
  4. platform default Unix socket path
  5. default TCP endpoint http://127.0.0.1:50052

Management authentication resolution is:

  1. --auth-token
  2. --auth-token-file
  3. SYNCTV_MANAGEMENT_AUTH_TOKEN
  4. SYNCTV_MANAGEMENT_AUTH_TOKEN_FILE
  5. management.auth_token or management.auth_token_file from config

When --endpoint or SYNCTV_MANAGEMENT_ENDPOINT is used, config-file auth is only used if a config source is explicitly selected with --config or SYNCTV_CONFIG_PATH. This avoids accidentally sending an auto-discovered local management token to an unrelated endpoint.

In containerized deployments, docker compose exec synctv synctv ... uses the same default Unix socket path inside the container. Use --endpoint only when intentionally targeting a non-default TCP or Unix socket listener.

Development

Docker Compose

# Local development build with fixed working defaults
docker compose -f docker-compose.dev.yml up -d

# Prebuilt image deployment
docker compose up -d

Run Tests

cargo nextest run --workspace

Run with Logging

SYNCTV_LOGGING_LEVEL=debug cargo run --bin synctv -- serve

For advanced tracing filters, prefer setting logging.filter in synctv.yaml or exporting SYNCTV_LOGGING_FILTER only for one-off diagnostics.

Build Release

cargo build --release --workspace

API

gRPC API

By default, public gRPC reflection is disabled. Enable it when you want to explore the API interactively with grpcurl:

export SYNCTV_SERVER_ENABLE_REFLECTION=true
cargo run --bin synctv -- serve

grpcurl -plaintext localhost:8080 list
grpcurl -plaintext localhost:8080 list synctv.client.ClientService

If you keep reflection disabled, use the checked-in protobuf definitions instead:

grpcurl -plaintext \
  -import-path synctv-proto/proto \
  -proto client.proto \
  localhost:8080 \
  synctv.client.ClientService/Login

Example: Register User

grpcurl -plaintext -d '{
  "username": "alice",
  "email": "alice@example.com",
  "password": "securepassword123"
}' localhost:8080 synctv.client.ClientService/Register

Example: Login

grpcurl -plaintext -d '{
  "username": "alice",
  "password": "securepassword123"
}' localhost:8080 synctv.client.ClientService/Login

Configuration

Configuration can be provided via:

  1. Environment variables (highest priority): SYNCTV_SECTION_KEY
  2. Config file (.yaml, .yml, .json, .toml), searched in platform-aware default locations such as: ./synctv.yaml, Linux $XDG_CONFIG_HOME/synctv/synctv.yaml or ~/.config/synctv/synctv.yaml, macOS ~/.synctv/synctv.yaml, Linux /etc/synctv/synctv.yaml, /config/synctv.yaml
  3. Defaults (lowest priority)

data_dir can also be set via CLI --data-dir, environment SYNCTV_DATA_DIR, or top-level config data_dir.

It affects only runtime-owned local paths:

  • management.unix_socket_path
  • logging.file_path
  • livestream.hls_storage_path
  • cache.proxy_slice_file_cache_dir

It does not affect static config inputs:

  • *_file secrets remain relative to the config file directory
  • metrics.tls.cert_path and metrics.tls.key_path remain relative to the config file directory

Absolute paths are preserved. Relative runtime-owned paths are resolved against the effective data directory.

Comprehensive Configuration File

A complete example config with documented options is provided in the repository. It includes:

  • All server, database, and Redis settings
  • WebRTC configuration for audio/video calls
  • OAuth2 provider examples (GitHub, Google, OIDC)
  • Livestream RTMP/HLS/FLV settings
  • Connection limits and security options
  • Production vs development guidance
  • Hundreds of lines of documented configuration

View the complete file: synctv.example.yaml

Quick Example (minimal configuration):

data_dir: "/var/lib/synctv"

server:
  host: "0.0.0.0"
  port: 8080

management:
  enabled: true
  transport: "unix"
  unix_socket_path: "/run/synctv/synctv.sock"  # Linux/container example

database:
  url: "postgresql://synctv:synctv@localhost:5432/synctv"
  max_connections: 100  # Increased for better performance

redis:
  url: "redis://localhost:6379"

jwt:
  secret: ""  # REQUIRED: Set via SYNCTV_JWT_SECRET env var

logging:
  level: "info"
  format: "pretty"  # Use "json" in production
  # filter: "info,synctv=debug"
  backtrace: false

Configuration Validation

Use the built-in validation tool to catch configuration errors before deployment:

# Validate synctv.yaml
cargo run --bin synctv -- config validate

# Validate specific file
cargo run --bin synctv -- config --config /path/to/synctv.yaml validate

What gets validated:

  • Syntax and structure (YAML parsing)
  • Required fields presence
  • JWT secret strength (minimum 256-bit entropy)
  • OAuth2 + Redis dependency
  • WebRTC cluster mode requirements
  • Permission hierarchy correctness
  • Network configuration validity

Use in CI/CD:

# GitHub Actions example
- name: Validate Configuration
  run: cargo run --bin synctv -- config validate

See docs/config-validation.md for detailed documentation.

Security

  • Password Hashing: Argon2id (PHC 2023 winner)
  • JWT: HS256 symmetric HMAC
  • Permissions: 64-bit bitmask system
  • TLS: Recommended for production

License

MIT OR Apache-2.0

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

Status

Current Status: Production-ready core features

Completed Features

  • User authentication (registration, login, JWT tokens)
  • Room management and real-time synchronization
  • Multi-provider media support (Bilibili, Alist, Emby)
  • Live streaming (RTMP push, HLS/FLV playback)
  • Multi-replica cluster support
  • OAuth2 integration (GitHub, Google, OIDC)
  • Permission system with 64-bit bitmask
  • WebSocket real-time communication

Completed Infrastructure

  • Cross-replica cache invalidation via Redis Streams (durable delivery with catch-up on reconnection)
  • Configuration validation tool with CI/CD integration

Next Milestone: Production hardening and performance optimization