Skip to content

irfanf16/stream-it

Repository files navigation

Stream-It — Live Streaming & Creator Monetization Platform

Laravel 9 + Inertia.js + React 18 platform for live video streaming, creator memberships, VOD sales, and fan tipping. Streamers broadcast via RTMP (OBS/Larix); viewers watch HLS playback. Virtual token economy with four payment gateways.

Laravel React Inertia.js Tailwind CSS Pusher Stripe


Table of Contents


What is Stream-It?

A creator monetization platform where:

  • Streamers go live via RTMP (OBS / Larix Broadcaster), sell memberships, upload paid VOD content, and accept private 1-on-1 paid sessions
  • Viewers buy token packs with real money, then spend tokens to tip, subscribe, purchase videos/galleries, and book private streams
  • Platform takes a 25% commission on video sales, gallery sales, and private streaming; tips go 100% to the streamer
  • Admin manages the full platform, processes payouts, configures payment gateways, and approves streamers

Tech Stack

Backend:

Package Purpose
Laravel 9 (^9.19) Core framework
Laravel Breeze Email/password auth scaffolding
Laravel Sanctum 2.8 API token auth
Inertia.js Laravel 0.6.3 Server-side Inertia bridge
Tightenco Ziggy Named routes in JavaScript
agence104/livekit-server-sdk ^1.1 RTMP webhook handling (LiveKit/media server)
ably/ably-php ^1.1 Ably broadcaster (alternative to Pusher)
pusher/pusher-php-server ^7.2 Pusher broadcaster
stripe/stripe-php ^10.11 Stripe Payment Intents
overtrue/laravel-follow 5.1 Polymorphic follow system
intervention/image 2.7 Profile/cover image processing
mews/purifier 3.3 HTML sanitization
league/flysystem-aws-s3-v3 S3 storage driver

Frontend:

Package Purpose
React 18.2.0 UI framework (via Inertia)
@inertiajs/inertia-react 0.8.1 Inertia React adapter
Vite 3.x + laravel-vite-plugin Build tool
Tailwind CSS 3.2 Styling
@headlessui/react 1.4 Accessible UI components
video.js 8.0.4 HLS video player
@stripe/react-stripe-js ^2.1.0 Stripe Payment Element
pusher-js ^8.0.1 + laravel-echo WebSocket client
react-toastify, react-icons Notifications + icons
react-google-recaptcha-v3 reCAPTCHA on registration

Architecture

Streamer (OBS/Larix)
    | RTMP broadcast
    v
Media Server (RTMP ingest -> HLS transcode)
    |                      |
    | webhook              | HLS segments (.m3u8)
    v                      v
POST /api/streaming/   Viewer browser
    validate-key       Video.js HLS player
    |
    v
LiveKitController
  set users.live_status = 'online'
  broadcast LiveStreamStarted event
    |
    v
Pusher / Ably (Laravel Echo)
    |
    v
All viewers receive live update

Broadcasting driver: BROADCAST_DRIVER=pusher or ably. Frontend uses Pusher JS client with Laravel Echo. Both backends fully configured — switch via env var.

Note: Agora RTC SDK (agora-rtc-sdk-ng, agora-react-uikit) is in package.json but NOT implemented anywhere in the React components. Streaming uses RTMP + HLS only.


Database Schema

Table Key Columns
users id, username, name, email, password, profile_picture, cover_picture, headline, about, tokens (wallet balance), is_streamer, is_streamer_verified, live_status (online/offline), is_admin, popularity
user_meta user_id, meta_key, meta_value — stores streaming_key, thanks_message, payout_destination, payout_details
tiers user_id (streamer), tier_name, perks, price (tokens/month), six_months_discount (%), one_year_discount (%)
subscriptions tier_id, streamer_id, subscriber_id, subscription_date, subscription_expires, status (Active/Canceled), subscription_tokens
token_packs name, tokens (int), price (double fiat)
token_sales user_id, tokens, amount, gateway, status (paid/pending)
tips user_id (tipper), streamer_id, tokens
chats roomName, streamer_id, user_id, tip (nullable), message, chat_type
private_streams streamer_id, user_id, tokens, stream_time, status (pending/accept/conform)
streaming_prices streamer_id, token_amount, streamer_time_id
streaming_times streamer_id, streaming_time (HH:MM)
videos user_id, title, thumbnail, video (path), price (tokens), free_for_subs, views, category_id
video_sales video_id, streamer_id, user_id, price (tokens after commission)
galleries user_id, title, thumbnail, price, free_for_subs, views
gallery_sales gallery_id, streamer_id, user_id, price
commissions admin_id, streamer_id, video_id, type (Buy Videos / Private Streaming), tokens (admin's 25% cut)
followables user_id, followable_type, followable_id, accepted_at (polymorphic)
withdrawals user_id, tokens, amount, status (Pending/Paid/Canceled)
room_bans streamer_id, user_id, ip
banned ip (global IP bans)
options_table option_name, option_value (key-value site config store)
categories category, icon (streamer categories: Youtuber, Tiktoker, etc.)
pages page_title, page_slug, page_content, page_type (page/post)
notifications Laravel polymorphic notifications

Live Streaming

Streamer Setup

  1. Streamer's unique RTMP key stored in user_meta (meta_key = 'streaming_key', format: {user_id}.{random16})
  2. Admin configures RTMP server URL in site settings (options_table)
  3. Streamer sets up OBS/Larix with: RTMP URL + their streaming key

Stream Start/Stop Webhook

Media server calls: POST /api/streaming/validate-key
  ?call=publish      -> stream started
  ?call=publish_done -> stream ended

LiveKitController::validateKey():
  publish:
    -> Look up user by streaming_key in user_meta
    -> Set users.live_status = 'online'
    -> Broadcast: LiveStreamStarted (room-{username} channel)
    -> Broadcast: LiveStreamRefresh (LiveStreamRefresh channel)

  publish_done:
    -> Set users.live_status = 'offline'
    -> Delete ALL chat messages for this room
    -> Broadcast: LiveStreamStopped
    -> Broadcast: LiveStreamRefresh

Viewer Playback

  • Video.js HLS player consuming {APP_URL}/livestreams/{roomName}.m3u8
  • Age gate: must be 18+ (checks users.dob) to enter a live stream room
  • Token gate: must have tokens > 0 to send chat messages

Real-time Events (WebSockets)

Event Class Channel Event Name Payload
LiveStreamStarted room-{username} (public) livestream.started channel
LiveStreamStopped room-{username} (public) livestream.stopped channel
LiveStreamRefresh LiveStreamRefresh (public) livestreams.refresh
LiveStreamBan room-{username} (public) livestream.ban
ChatMessageEvent room-{username} (public) livechat full Chat model
LivePrivateStreamStarted room-{username} (public) private.livestream.started user, privateStream, chat

Note: Chat messages are ephemeral — they are deleted when a stream ends (LiveStreamStopped triggers Chat::where('streamer_id', $id)->delete()).


Token Economy

Tokens are an internal virtual currency (users.tokens integer column). Exchange rate configured by admin in options_table (token_value).

Earning Tokens (Streamers)

Source Streamer Gets Platform Gets
Tips in live chat 100% 0%
Video purchases 75% 25% (in commissions table)
Gallery purchases 75% 25%
Private streaming 75% 25%
Subscriptions 100% 0%

Spending Tokens (Viewers)

  • Tips: Any amount >= 1 token, instant transfer
  • Subscriptions: Monthly / 6-month / yearly (discounts via tier settings)
  • Videos: Per-video token price; free_for_subs = yes = free for active subscribers
  • Galleries: Per-gallery price; free for subs optionally
  • Private streams: Token amount per configured session duration

Buying Tokens (Fiat)

Admin defines token packs in token_packs table (e.g. Starter: 100 tokens for $90, Platinum: 5000 tokens for $3900). Purchasable via 4 gateways.

Withdrawing Earnings

Streamers request payout (minimum threshold from min_withdraw option). Admin manually processes and marks as Paid. Payout destination stored in user_meta.


Payment Gateways

All four gateways handle token pack purchases only. Subscriptions/tips/video purchases use tokens (no direct fiat).

Gateway Flow Integration
Stripe React Stripe.js Payment Element -> PaymentIntent -> redirect to /stripe/order-complete stripe/stripe-php + @stripe/react-stripe-js
PayPal IPN redirect flow -> POST /api/paypal/ipn validates with PayPal IPN server Direct cURL (no SDK)
CCBill Server-side redirect to FlexForms with MD5 hash -> ANY /api/ccbill/webhooks MD5 hash verification, handles NewSaleSuccess event; supports USD, EUR, AUD, CAD, GBP, JPY
Bank Transfer Manual: user uploads payment proof -> admin approves Image upload + admin review

Private Streaming (1-on-1)

1. Streamer configures packages: streaming_prices (tokens) + streaming_times (duration)

2. Viewer sends request: POST /api/chat/send-private-request
   -> Tokens deducted from viewer IMMEDIATELY
   -> Tokens credited to streamer IMMEDIATELY
   -> private_streams record created (status = 'pending')

3. Streamer accepts: GET /api/chat/accept-streaming/{id}
   -> status = 'accept'
   -> Unique room created: private-{timestamp}_{username}
   -> Broadcasts LivePrivateStreamStarted event

4. Session ends: POST /api/chat/finished-streaming-chat
   -> status = 'conform'
   -> 25% commission recorded in commissions table
   -> Credits admin account with commission tokens

5. Cancel: triggers full token refund to viewer

Note: Stream visibility is controlled at the React level (checking chat_type and participant IDs), not at the media server level — same RTMP stream is used.


User Roles

Role How Determined Access
Visitor Not authenticated Browse channels, view stream pages
User Authenticated, is_streamer = 'no' Buy tokens, tip, subscribe, purchase content, send private requests
Streamer is_streamer = 'yes' + is_streamer_verified = 'yes' Go live, sell content, accept private sessions, request payouts
Admin is_admin = 'yes' Full admin panel at /admin/*

Streamer verification: User submits government ID image -> admin approves via admin panel -> sets is_streamer_verified = 'yes' -> sends StreamerVerifiedNotification email.


Route Structure

Web Routes (Inertia - React frontend):
  GET  /                    Homepage (live channels preview)
  GET  /channel/{user}      Streamer profile
  GET  /channel/live-stream/{user}  Live stream viewer (18+ + token gate)
  GET  /browse-channels/{category?} Browse all channels
  GET  /browse-videos       VOD catalog
  GET  /browse-gallery      Gallery catalog
  GET  /get-tokens          Token purchase page
  GET  /membership/...      Membership tier management (streamers)
  GET  /streamer/verify     Verification submission form
  GET  /withdrawals         Payout management

Payment Routes:
  GET  paypal/purchase/{pack}       PayPal redirect
  GET  stripe/purchase/{pack}       Stripe payment page
  GET  ccbill/purchase/{pack}       CCBill redirect
  GET  bank-transfer/purchase/{pack}

API Routes:
  POST /api/streaming/validate-key  RTMP webhook (stream start/stop)
  POST /api/streaming/update-status
  GET  /api/chat/latest-messages/{room}
  POST /api/chat/send-message/{user}
  POST /api/chat/send-private-request
  GET  /api/chat/accept-streaming/{id}
  GET  /api/follow/{user}           Toggle follow
  GET  /api/search                  Channel/user search
  POST /api/paypal/ipn              PayPal webhook
  ANY  /api/ccbill/webhooks         CCBill webhook
  POST /api/upload-video-chunks     Chunked video upload

Admin Panel

Custom Blade-rendered panel at /admin/*:

  • Dashboard stats
  • User management (token balance, roles, ban/unban, impersonation)
  • Streamer verification approval
  • Payout processing
  • Token pack CRUD
  • Token sales log + manual grant
  • Subscription management
  • Video/gallery management
  • Category management
  • Payment gateway configuration (enable/disable Stripe/PayPal/CCBill/Bank)
  • Site settings (title, SEO, token value, commission rate, min withdrawal)
  • RTMP + chat + mail + cloud configuration
  • Commission/earning reports
  • Bulk email sender + tag pixels

Getting Started

composer install
npm install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan serve
npm run dev

Key environment variables:

BROADCAST_DRIVER=pusher          # or: ably
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=

RTMP_URL=rtmp://your-media-server/live

STRIPE_KEY=
STRIPE_SECRET=

CCBILL_SALT_KEY=
CCBILL_ACC_NO=
CCBILL_SUBACC_NO=
CCBILL_FLEX_FORM_ID=

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=
AWS_BUCKET=

GOOGLE_RECAPTCHA_KEY=

About

Real-time streaming platform — Laravel 9, Inertia.js, React, Agora RTC, Ably, Stripe/PayPal/CCBill, token economy, LiveKit

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors