Skip to content

RichardDally/RTube

Repository files navigation

RTube

Streaming platform Proof Of Concept.

Prerequisites

Installation

Option 1: Docker (Recommended)

Pull and run the official Docker image:

docker pull richarddally/rtube:latest
docker run -p 5000:5000 richarddally/rtube:latest

Or use docker-compose:

services:
  rtube:
    image: richarddally/rtube:latest
    ports:
      - "5000:5000"
    volumes:
      - ./data:/home/richard/data
    environment:
      - RTUBE_SECRET_KEY=your-secret-key

Option 2: Manual Installation

1. Install Python dependencies

Using uv (recommended):

uv sync

2. Install Node.js dependencies

cd rtube/static
npm install

Usage

Generate HLS playlist

Convert your MP4 video to HLS format:

python mp4_to_hls.py

This can take some time depending on your CPU.

Run the server

flask --app rtube run

Then open http://127.0.0.1:5000 in your browser.

Features

Video Player

  • HLS streaming with adaptive quality selection
  • Keyboard shortcuts (hotkeys)
  • Video markers support
  • Timestamp sharing via URL parameter (?t=120 for 2 minutes)
  • Theater mode (wider view, press T or click button) - preference saved

Video Management

  • Upload and encode videos to HLS format
  • Video visibility (public/private)
  • Video deletion by owner or admin
  • Thumbnail generation
  • Video preview on hover (WebM clips)
  • View count tracking
  • Recommended videos sidebar
  • Watch history with resume playback

Comments

  • Post, edit, and delete comments on videos
  • Threaded replies (nested comments)
  • Soft delete with "[deleted]" placeholder
  • Sort by newest or oldest
  • YouTube-style collapsible replies
  • Automatic URL detection and linking (urlize)
  • Character limit (5000 characters)

Playlists

  • Create and manage custom playlists
  • Add/remove videos from playlists
  • Reorder videos within playlists
  • Public playlist viewing

Favorites

  • Mark videos as favorites
  • Quick access to favorite videos from profile

Search

  • Search videos by title, description, or author
  • Results grouped by match type

Share Button

Each video page includes a share button with two options:

  • Copy link - Copies the video URL to clipboard
  • Copy link at timestamp - Copies the URL with ?t= parameter set to current playback position

The button provides visual feedback when the URL is copied. Shared timestamp links automatically start playback at the specified time.

Environment Variables

Variable Description Default
RTUBE_DATABASE_URL Database connection URL (PostgreSQL recommended for production) sqlite:///rtube.db
RTUBE_AUTH_DATABASE_URL Authentication database URL (separate for security) sqlite:///rtube_auth.db
RTUBE_SECRET_KEY Secret key for session security (generate a strong random key for production) Auto-generated
RTUBE_HTTPS Enable secure session cookies (true, 1, or yes when using HTTPS) false
RTUBE_KEEP_ORIGINAL_VIDEO Keep original MP4 file after encoding (true, 1, or yes to enable) false
RTUBE_INSTANCE_PATH Custom path for instance folder (sessions, secret key). Must be an absolute path. instance/
RTUBE_OIDC_ENABLED Enable OIDC authentication (true, 1, or yes) false
RTUBE_OIDC_CLIENT_ID OAuth2/OIDC client ID -
RTUBE_OIDC_CLIENT_SECRET OAuth2/OIDC client secret -
RTUBE_OIDC_DISCOVERY_URL OIDC discovery endpoint URL (.well-known/openid-configuration) -
RTUBE_OIDC_SCOPES Space-separated OAuth2 scopes openid profile email
RTUBE_OIDC_USERNAME_CLAIM Claim to use for username preferred_username
RTUBE_OIDC_REDIRECT_URI Redirect URI for OIDC callback http://127.0.0.1:5000/auth/oidc/callback
REQUESTS_CA_BUNDLE Path to custom CA certificate bundle for OIDC provider (standard Python env var) System CA bundle

Authentication

RTube includes a built-in authentication system with four user roles:

  • Anonymous: Can view public videos only (not logged in)
  • Viewer: Can view videos, create playlists, and add favorites, but cannot upload
  • Uploader: Can view and upload videos, encode videos, manage own content
  • Admin: Full access including user management, role changes, and moderation

User Profiles

Each user has a profile page accessible at /profile (own profile) or /profile/<username> (any authenticated user). Profiles display:

  • Uploaded videos with thumbnails and view counts
  • Posted comments with links to the videos

Admin Features

Administrators have access to the Admin dropdown menu which provides:

User Management (/admin/users)

  • List of all registered users with their roles
  • Online/offline status based on recent activity
  • Video, comment, playlist, and favorite counts per user
  • Role management: change user roles (Viewer, Uploader, Admin)
  • Direct links to user profiles for moderation
  • Password change for admin account

Import Videos (/admin/import-videos)

  • Scan for orphan encoded videos (HLS files not in database)
  • Display available quality variants for each video
  • Bulk import with automatic thumbnail generation
  • Videos are imported as private by default

Video Management (/admin/videos)

  • List all videos with filters (visibility, owner, sort)
  • Bulk actions: delete, make public, make private
  • Quick access to video editing and viewing

Regenerate Previews (/admin/regenerate-previews)

  • List videos missing preview clips
  • Bulk generate WebM previews for hover display

Analytics Dashboard (/admin/analytics)

  • Platform statistics (videos, users, comments, views)
  • Activity chart with configurable periods (30 days to 5 years)
  • Storage usage breakdown
  • Top videos, uploaders, and commenters
  • Encoding job statistics
  • Week-over-week comparisons

Audit Log (/admin/audit-log)

  • Track all admin actions with timestamps
  • Filter by action type or admin user
  • Records IP addresses and action details
  • Paginated view with full history

Video Editing (/watch/edit)

  • Admins can edit any video (not just their own)
  • Change video owner to any Uploader or Admin user

Session Persistence

User sessions persist across server restarts. Sessions are stored server-side using Flask-Session with filesystem storage. The secret key is automatically generated and saved to instance/.secret_key on first run.

Storage

All media files are stored in the instance/ folder:

  • instance/videos/ - HLS video files (.m3u8 and .ts segments)
  • instance/thumbnails/ - Video thumbnail images
  • instance/sessions/ - User session data
  • instance/.secret_key - Persistent secret key

Use RTUBE_INSTANCE_PATH to customize the storage location.

Default Admin Account

On first startup, a default admin account is created:

  • Username: admin
  • Password: admin

Important: Change this password immediately in production!

Password Requirements

  • Minimum 12 characters
  • At least one uppercase letter (A-Z)
  • At least one lowercase letter (a-z)
  • At least one digit (0-9)
  • At least one special character
  • No common patterns or sequences

OIDC Authentication (SSO)

RTube supports Single Sign-On via OpenID Connect (OIDC). This works with any OIDC-compliant identity provider (Keycloak, Authentik, Azure AD, Okta, Google, etc.).

Configuration Example

export RTUBE_OIDC_ENABLED=true
export RTUBE_OIDC_CLIENT_ID="rtube"
export RTUBE_OIDC_CLIENT_SECRET="your-client-secret"
export RTUBE_OIDC_DISCOVERY_URL="https://auth.example.com/realms/master/.well-known/openid-configuration"
export RTUBE_OIDC_SCOPES="openid profile email"
export RTUBE_OIDC_USERNAME_CLAIM="preferred_username"

How it Works

  1. User clicks "Sign in with SSO (OIDC)" on the login page
  2. User is redirected to the Identity Provider (IdP)
  3. After successful authentication, IdP redirects back to RTube
  4. RTube creates a local user account on first login (with uploader role)
  5. User is logged in

OIDC users can also use local credentials if they have a local account.

Custom CA Certificate

If your OIDC provider uses a self-signed certificate or a certificate signed by a private CA, you need to configure RTube to trust it. Flask-OIDC uses Python's requests library, which respects standard environment variables for CA certificates:

export REQUESTS_CA_BUNDLE=/path/to/custom-ca-bundle.pem

Creating a combined CA bundle:

If you need to trust both system CAs and your custom CA:

# Linux/macOS
cat /etc/ssl/certs/ca-certificates.crt /path/to/your-ca.pem > /path/to/combined-ca-bundle.pem
export REQUESTS_CA_BUNDLE=/path/to/combined-ca-bundle.pem

# Or add your CA to the system trust store (requires root)
sudo cp your-ca.pem /usr/local/share/ca-certificates/your-ca.crt
sudo update-ca-certificates

Docker deployment:

When running RTube in Docker with a private CA:

FROM python:3.11-slim
COPY your-ca.pem /usr/local/share/ca-certificates/your-ca.crt
RUN update-ca-certificates
# ... rest of your Dockerfile

Testing OIDC Locally

For local development and testing, you can use one of these OIDC providers:

Option 1: Authentik (Recommended)

Authentik is an open-source identity provider that's easy to set up with Docker.

# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
  postgresql:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - database:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: authentik
      POSTGRES_USER: authentik
      POSTGRES_DB: authentik

  redis:
    image: redis:alpine
    restart: unless-stopped

  server:
    image: ghcr.io/goauthentik/server:latest
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: authentik
      AUTHENTIK_SECRET_KEY: "generate-a-random-secret-key-here"
    ports:
      - "9000:9000"
      - "9443:9443"
    depends_on:
      - postgresql
      - redis

  worker:
    image: ghcr.io/goauthentik/server:latest
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: authentik
      AUTHENTIK_SECRET_KEY: "generate-a-random-secret-key-here"
    depends_on:
      - postgresql
      - redis

volumes:
  database:
EOF

# Start Authentik
docker compose up -d

Then:

  1. Open http://localhost:9000/if/flow/initial-setup/ to create admin account
  2. Create a new OAuth2/OIDC Provider in Admin > Providers
  3. Create an Application linked to this provider
  4. Configure RTube with the client credentials
Option 2: Keycloak
docker run -p 8080:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:latest start-dev

Then:

  1. Open http://localhost:8080 and log in with admin/admin
  2. Create a new Realm (e.g., "rtube")
  3. Create a new Client with:
    • Client ID: rtube
    • Client authentication: ON
    • Valid redirect URIs: http://127.0.0.1:5000/auth/oidc/callback
  4. Copy the client secret from Credentials tab
  5. Configure RTube:
    export RTUBE_OIDC_ENABLED=true
    export RTUBE_OIDC_CLIENT_ID="rtube"
    export RTUBE_OIDC_CLIENT_SECRET="your-client-secret"
    export RTUBE_OIDC_DISCOVERY_URL="http://localhost:8080/realms/rtube/.well-known/openid-configuration"
Option 3: mock-oidc-server (Lightweight)

For quick testing without a full IdP, you can use a mock OIDC server:

# Using Node.js
npx mock-oidc-server --port 9090

# Or using Python
pip install oidc-provider
python -m oidc_provider

Note: Mock servers are for development only - never use in production!

Database Migrations

RTube uses Flask-Migrate (Alembic) to manage database schema changes.

For New Installations

If you're setting up RTube for the first time, the database will be created automatically when you start the application. Then stamp the database to mark it as up-to-date:

flask --app rtube.app:create_app db stamp head

Applying Migrations

After pulling new changes that include database migrations:

flask --app rtube.app:create_app db upgrade

Auth Database Migrations

The users table is stored in a separate auth database (rtube_auth.db or PostgreSQL). Flask-Migrate only manages the main database, so auth schema changes must be applied manually.

For role column (if upgrading from older version):

The role column should already exist with default value uploader. Valid roles are: viewer, uploader, admin.

Creating New Migrations

When you modify the data models (models.py or models_auth.py):

  1. Auto-generate a migration based on model changes:

    flask --app rtube.app:create_app db migrate -m "Description of changes"
  2. Review the generated migration in migrations/versions/ before applying it.

  3. Apply the migration:

    flask --app rtube.app:create_app db upgrade

Common Commands

Command Description
flask db upgrade Apply all pending migrations
flask db downgrade Revert the last migration
flask db current Show current migration revision
flask db history Show migration history
flask db stamp head Mark database as up-to-date without running migrations

Note: Always use --app rtube.app:create_app with Flask commands, or set the FLASK_APP environment variable:

export FLASK_APP=rtube.app:create_app  # Linux/macOS
set FLASK_APP=rtube.app:create_app     # Windows

Publishing to PyPI and Docker Hub

RTube includes a GitHub Actions workflow to build and publish packages to PyPI and Docker Hub.

PyPI Setup (Trusted Publishing)

  1. Configure Trusted Publisher on PyPI:

    • Go to PyPI Publishing Settings
    • Click "Add a new pending publisher" (for new projects) or configure on the project page (for existing projects)
    • Fill in the form:
      • PyPI Project Name: rtube
      • Owner: your GitHub username or organization
      • Repository name: RTube
      • Workflow name: publish.yml
      • Environment name: pypi
    • Click "Add"
  2. Create a GitHub Environment:

    • Go to your repository on GitHub
    • Navigate to Settings > Environments
    • Click New environment
    • Name: pypi (must match the name configured on PyPI)
    • Add protection rules if desired (e.g., required reviewers)

No API tokens or secrets are required for PyPI - authentication is handled automatically via OIDC.

Docker Hub Setup

  1. Create a Docker Hub Access Token:

    • Log in to Docker Hub
    • Go to Account Settings > Security > Access Tokens
    • Click New Access Token
    • Name: github-actions (or any descriptive name)
    • Permissions: Read, Write, Delete
    • Click Generate and copy the token
  2. Add GitHub Secrets:

    • Go to your repository on GitHub
    • Navigate to Settings > Secrets and variables > Actions
    • Add two secrets:
      • DOCKERHUB_USERNAME: Your Docker Hub username
      • DOCKERHUB_TOKEN: The access token generated above

Triggering a Release

Option 1: Manual trigger with semantic version bump (recommended)

  1. Go to Actions > Build and Publish
  2. Click Run workflow
  3. Select the bump type:
    • PATCH (0.2.0 → 0.2.1) - Bug fixes
    • MINOR (0.2.0 → 0.3.0) - New features
    • MAJOR (0.2.0 → 1.0.0) - Breaking changes
  4. Click Run workflow

The workflow will automatically:

  • Read the current version from rtube/__version__.py
  • Bump the version based on your selection
  • Update both rtube/__version__.py and pyproject.toml
  • Commit the changes and create a git tag (e.g., v0.3.0)
  • Build and publish to PyPI and Docker Hub

Option 2: Push a version tag manually

git tag v0.3.0
git push origin v0.3.0

Workflow Steps

  1. Bump Version (manual trigger only): Updates version in source files, commits, and creates tag
  2. Build Wheel: Runs pytest, then creates wheel and sdist using uv build
  3. Build Docker: Builds Docker image using the wheel (validates image builds correctly)
  4. Publish to PyPI: Uploads packages using OIDC trusted publishing (only after Docker build succeeds)
  5. Push Docker: Pushes Docker image to Docker Hub (only after Docker build succeeds)
  6. Create GitHub Release: Creates a release with the built artifacts (only after PyPI and Docker Hub publish succeed)
  7. Rollback on failure: Logs errors and provides guidance if any step fails

Git LFS side note

  • Download and install Git Large File Storage
  • Track mp4 files $ git lfs track "*.mp4"
  • git add/commit/push will upload on GitHub LFS.

About

Streaming platform POC

Resources

License

Stars

Watchers

Forks