Skip to content

CasRepoClone/SnuggleStream

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SnuggleStream
SnuggleStream

Watch videos together, perfectly in sync. No accounts, no hassle — just create a room, share the code, and enjoy.

  • This was generated by Claude Opus4.6 and modified by myself
  • my girlfriend was getting mad that we had speakers issues so I made this.
  • Promising results nad custom CI/CD github actions pipeline for fun for going from problem to solution within 8 hours

Features

  • Synchronized Playback — Play, pause, and seek sync across all viewers in real time via WebSocket
  • Multiple Video Sources — Load from a URL (.mp4, .webm, .m3u8), upload a file, or set the video later
  • Screen Sharing — Share your screen or an application window with viewers via WebRTC peer-to-peer streaming (host only)
  • Stream Quality Settings — Cogwheel menu to adjust video bitrate (500 kbps – 6 Mbps) and audio bitrate (64 – 510 kbps) during screen share
  • Room System — Create rooms with a 6-character code, share with friends, no login required
  • Live Chat — Built-in chat sidebar with nickname support
  • Custom Controls — Full video player with progress bar, volume, playback speed, and fullscreen
  • Help Tooltips — Hover over ? icons next to settings for contextual help with animated, backdrop-blurred tooltips
  • Keyboard Shortcuts — Space/K (play/pause), F (fullscreen), M (mute), Arrow keys (±10s seek)
  • Responsive Design — Works on desktop and mobile

Project Structure

SnuggleStream/
├── app/
│   ├── __init__.py
│   ├── auth.py            # Google OAuth2 authentication
│   ├── config.py          # App settings and paths
│   ├── main.py            # FastAPI app factory
│   ├── moderation.py      # Chat moderation
│   ├── rooms.py           # Room manager (in-memory state)
│   ├── security.py        # Security middleware
│   ├── transcode.py       # HLS transcoding (FFmpeg)
│   └── routers/
│       ├── __init__.py
│       ├── api.py          # REST API endpoints
│       ├── auth.py         # Auth routes
│       ├── pages.py        # HTML page routes
│       └── ws.py           # WebSocket sync + WebRTC signalling
├── static/
│   ├── css/
│   │   └── style.css       # All styles (dark theme)
│   └── js/
│       ├── home.js         # Home page logic
│       └── room.js         # Room page + video sync + screen share
├── templates/
│   ├── index.html          # Home page (create/join)
│   └── room.html           # Room page (player + chat)
├── media/                  # Uploaded videos (auto-created, gitignored)
├── requirements.txt
├── run.py                  # Dev entry point
├── .env.example
└── .gitignore

Quick Start

Prerequisites

  • Python 3.10+

Installation

# Clone or navigate to the project
cd SnuggleStream

# Create virtual environment
python -m venv venv

# Activate (Windows)
venv\Scripts\activate
# Activate (Linux/Mac)
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

Run (Development)

python run.py

The app starts at http://localhost:8000.

Run (Production on VPS)

pip install -r requirements.txt

# Run with uvicorn directly
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1

# Or behind a reverse proxy (recommended):
# Use Nginx/Caddy to proxy http + websocket to port 8000

Important: Use --workers 1 because rooms are stored in-memory. Multiple workers would create separate room stores. For scaling, add Redis-backed room storage.

Nginx Example Config

server {
    listen 80;
    server_name your-domain.com;

    client_max_body_size 2G;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400;
    }
}

Environment Variables

Variable Default Description
HOST 0.0.0.0 Bind address
PORT 8000 Server port
ROOM_EXPIRY_HOURS 24 Hours before empty rooms expire

How It Works

  1. Create a Room — Pick a name, optionally add a video URL or upload a file
  2. Share the Code — A 6-character room code is generated (e.g., ABC123)
  3. Watch Together — Anyone who joins sees the same video at the same position
  4. Sync Events — When anyone plays, pauses, or seeks, a WebSocket message is broadcast to all other viewers
  5. Chat — Send messages in the sidebar chat

Screen Sharing

The host can share their screen or a specific application window directly with all viewers using WebRTC peer-to-peer connections.

  • Select Screen Share as the source when creating a room, or switch to the Screen Share tab inside a room
  • Audio is captured with high-quality settings (48 kHz stereo, no noise suppression)
  • Use the cogwheel icon (⚙) in the player controls to adjust video and audio bitrate on the fly
  • Viewers receive the stream automatically — no extra setup needed
  • Screen share stops when the host clicks Stop or closes the browser share prompt

API Endpoints

Method Path Description
GET / Home page
GET /room/{code} Room page
POST /api/rooms Create a room
GET /api/rooms List active rooms
GET /api/rooms/{code} Get room info
POST /api/upload Upload a video file
WS /ws/{room_code} WebSocket sync connection

License

MIT

CI/CD — Auto-Deploy on Push

A GitHub Actions workflow is included at .github/workflows/deploy.yml. Every push to main will SSH into your VPS, pull the latest code, install dependencies, and restart the service.

Prerequisites

  • A VPS running the app at /opt/snugglestream with the snugglestream systemd service
  • Git initialised on the VPS with your GitHub repo as the origin remote

1. Set up the VPS repo

SSH into your server and run:

cd /opt/snugglestream
git init
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git
git fetch origin main
git reset --hard origin/main

2. Generate a deploy SSH key

On your local machine:

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N ""

Add the public key to your VPS:

ssh-copy-id -i ~/.ssh/deploy_key.pub root@YOUR_SERVER

Or manually:

cat ~/.ssh/deploy_key.pub | ssh root@YOUR_SERVER "cat >> ~/.ssh/authorized_keys"

3. Add the secret to GitHub

  1. Go to your repo → SettingsSecrets and variablesActions
  2. Click New repository secret
  3. Name: VPS_SSH_KEY
  4. Value: paste the contents of ~/.ssh/deploy_key (the private key, including the BEGIN and END lines)

4. Update the workflow (if needed)

Open .github/workflows/deploy.yml and set your server's hostname and SSH user if they differ from the defaults.

That's it

Push to main and the workflow will:

1.#SSH into your server 3. git fetch + git reset --hard to the latest commit 4. pip install -r requirements.txt 5. systemctl restart snugglestream

This code falls under

GNU Affero General Public License v3

e

About

Synchronized watch party platform with real-time video sync, HLS adaptive streaming, chat with GIF support, and Google OAuth;built with FastAPI and WebSockets.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors