A video host that respects your time. Built entirely on Cloudflare infrastructure — zero external dependencies for core functionality.
Note on infra naming. The product was rebranded from "Cloudflare Tube" to spooool. The underlying R2 bucket (
cloudflare-tube-videos) and D1 database (cloudflare-tube-prod) still use the legacy names; rename in Cloudflare and updatewrangler.tomlif you want them aligned.
┌──────────────────────────────────────────────────────────────────────────────┐
│ Cloudflare Edge Network │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────────┐ │
│ │ Workers │──────│ Durable │──────│ D1 Database │ │
│ │ (Frontend │ │ Objects │ │ (Metadata) │ │
│ │ + API) │ │ (Cache+ │ │ │ │
│ └──────────────────┘ │ State) │ └────────────────────┘ │
│ │ └──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────────┐ │
│ │ Pages │ │ Stream │──────│ R2 Storage │ │
│ │ (Hosting) │ │ (Encoding) │ │ (Videos) │ │
│ └──────────────────┘ └──────────────────┘ └────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
| Component | Purpose | Cost |
|---|---|---|
| Workers | Frontend (React SPA), Video API, Auth, Upload handler | $0.15/million requests |
| Pages | Static site hosting | Free |
| Stream | Video encoding/transcoding to HLS | $5-20/1000 min stored + $1/1000 min delivered |
| R2 | Raw video storage (no egress fees) | $0.015/GB/month stored |
| D1 | Video metadata, user data, playlists | Free tier (500k reads/writes) |
| Durable Objects | Session management, rate limiting, real-time features | $0.15/million ops |
| KV | Cache layer, temporary uploads | Free tier (100k reads/day) |
For cost-conscious deployment:
- Use R2 + FFmpeg Worker for local encoding
- Generate HLS manifests on the fly
- Serve pre-encoded video tiers from R2
- Est. Cost: $0.015-0.05/GB/month (no transcoding fees)
- ✅ Upload videos to R2 via Web UI
- ✅ Automatic encoding with Stream or local FFmpeg
- ✅ HLS video playback with adaptive bitrate
- ✅ Video browsing and search (D1 database)
- ✅ Responsive web player
- ✅ Channel/creator support
- ✅ View counts and engagement metrics
- Comments and nested replies (D1)
- Playlists and watch history (D1 + KV)
- User subscriptions (Durable Objects for real-time)
- Live streaming (Stream Live API)
- Analytics dashboard
- Content moderation queue
- Video recommendations engine
- Social features (likes, shares, pins)
- Premium memberships (Stripe integration)
- Channel monetization (Stripe Connect)
- Creator studio dashboard
- Advanced analytics
- A/B testing framework
- Cloudflare account with Stream enabled
- Wrangler CLI installed
- Node.js 16+
- FFmpeg (if using local encoding path)
# Clone and install
git clone https://github.com/aloewright/spooool.git
cd spooool
npm install
# Configure Wrangler
wrangler login
# Create R2 bucket
wrangler r2 bucket create cloudflare-tube-videos
# Deploy database schema (includes better-auth tables)
wrangler d1 migrations apply cloudflare-tube-prod
# Set the better-auth signing secret (32+ random bytes)
openssl rand -hex 32 | wrangler secret put BETTER_AUTH_SECRET
# Deploy workers
wrangler deployCLOUDFLARE_ACCOUNT_ID=your_account_id
CLOUDFLARE_API_TOKEN=your_api_token
CLOUDFLARE_ZONE_ID=your_zone_id
CF_STREAM_TOKEN=your_stream_token
R2_BUCKET_NAME=cloudflare-tube-videos
R2_BUCKET_DOMAIN=https://yourdomain.r2.cloudflareaaccess.com
DATABASE_URL=postgresql://... # Only if using external DBspooool/
├── src/
│ ├── api/ # Workers endpoints
│ │ ├── videos.ts # Video CRUD operations
│ │ ├── upload.ts # Upload handler
│ │ ├── stream.ts # Stream API wrapper
│ │ ├── auth.ts # Authentication
│ │ └── search.ts # Video search
│ ├── workers/
│ │ ├── index.ts # Main Worker entry
│ │ ├── middleware.ts # Auth, CORS, etc
│ │ └── encoding.ts # FFmpeg encoding (R2 path)
│ ├── frontend/ # React SPA
│ │ ├── components/ # Video player, upload, etc
│ │ ├── pages/ # Watch, browse, channel
│ │ └── App.tsx
│ └── db/
│ ├── schema.sql # D1 database schema
│ └── migrations/
├── wrangler.toml # Wrangler configuration
├── package.json
└── README.md
name = "spooool"
type = "javascript"
account_id = "your_account_id"
workers_dev = true
route = "api.spooool.com/*"
[env.production]
route = "api.spooool.com/*"
[[r2_buckets]]
binding = "VIDEOS"
bucket_name = "cloudflare-tube-videos"
[[d1_databases]]
binding = "DB"
database_name = "cloudflare-tube-prod"
database_id = "your_database_id"
[[kv_namespaces]]
binding = "CACHE"
id = "your_kv_namespace_id"
[[durable_objects.bindings]]
name = "RATE_LIMITER"
class_name = "RateLimiter"
script_name = "spooool"
[env.production.env]
ENVIRONMENT = "production"
API_HOST = "https://api.spooool.com"# Development
wrangler dev
# Production
wrangler deploy --env production
# Create Pages project
wrangler pages project create spooool-web
# Deploy frontend
wrangler pages deploy ./dist --project-name spooool-web# Enable Stream API in Cloudflare Dashboard
# Then configure in wrangler.toml with Stream API token# Deploy encoding Worker separately
wrangler deploy --name spooool-encoder
# Or use scheduled Worker for batch encoding
# Configure in wrangler.toml:
[triggers]
crons = ["0 */4 * * *"] # Run every 4 hoursPOST /api/videos/upload # Upload video
GET /api/videos/:id # Get video details
GET /api/videos # List/search videos
PUT /api/videos/:id # Update metadata
DELETE /api/videos/:id # Delete video
GET /api/videos/:id/stream # Get HLS stream URL
POST /api/auth/register # Register user
POST /api/auth/login # Login
POST /api/auth/logout # Logout
GET /api/auth/me # Get current user
GET /api/channels/:username # Get channel
PUT /api/channels/:username # Update channel
POST /api/channels/:username/follow # Follow channel
GET /api/channels/:username/videos # Get channel videos
1. Upload video → R2
2. POST /api/videos/upload with R2 path
3. Trigger Stream encoding
4. Stream processes and stores HLS in R2
5. Get manifest URL from Stream API
6. Client plays via HLS manifest
1. Upload video → R2 (raw)
2. Scheduled Worker triggers encoding
3. FFmpeg container encodes to HLS
4. Store output segments + manifest in R2
5. Generate signed URLs
6. Client plays via R2-hosted HLS manifest
- Cache video manifests: 1 hour (KV)
- Cache metadata: 10 minutes (KV)
- Cache search results: 5 minutes (KV)
- Edge caching via Stream CDN
- Chunked upload to R2 (5MB chunks)
- Parallel chunk uploads
- Resume capability via R2 API
- Adaptive bitrate (HLS variants)
- Preload next chunk
- Connection adaptive switching
- Geographic edge routing
| Component | Usage | Cost |
|---|---|---|
| Workers | 100k requests | $0.015 |
| Stream (if used) | 1GB stored + 10k plays | $7-15 |
| R2 Storage | 1GB | $0.015 |
| D1 | 50k queries | Free |
| KV Cache | 10k reads | Free |
| Total | $7.03-15.03/month |
- Storage: $0.015/GB/month
- Compute: $0.15 per 100k CPU-ms (FFmpeg)
- Est. total: $0.50-2/month at 10k views
- ✅ Token-based auth (JWT in KV)
- ✅ CORS validation on all endpoints
- ✅ Rate limiting via Durable Objects
- ✅ Signed R2 URLs (time-limited)
- ✅ Content security policies
- ✅ DDoS protection via Cloudflare
⚠️ TODO: DMCA takedown handling⚠️ TODO: Content moderation API
# Check Stream status
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_id} \
-H "Authorization: Bearer {token}"
# Check R2 upload
wrangler r2 object list cloudflare-tube-videos- Verify Stream is enabled (R2 → Stream egress is free)
- Or switch to R2-only path with local FFmpeg
- Use signed URLs with CF cache
- Break uploads into chunks
- Use Queue for async processing
- Deploy separate encoding Worker
Contributions welcome! Areas needing help:
- Video player UI improvements
- Comment system implementation
- Search ranking algorithm
- Encoding optimization
- Mobile app (Tauri)
- MVP with Stream encoding (Week 1-2)
- R2-only local encoding path (Week 2-3)
- Authentication system (Week 3)
- Channel/creator system (Week 4)
- Analytics dashboard (Week 4)
- Live streaming support (Week 5)
- Mobile app with Tauri (Week 6+)
MIT - Build your own video platform!
- Cloudflare Workers Docs
- Cloudflare Stream Docs
- Cloudflare R2 Docs
- Cloudflare D1 Docs
- Video.js Documentation
- HLS Streaming Guide
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: support@spooool.com
Building the future of video on Cloudflare 🚀