Skip to content

Latest commit

 

History

178 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StreamHub

A self-hosted streaming aggregator that searches movieffm, 777tv, and dramasq simultaneously, validates HLS sources, and plays them in-browser — no ads, no redirects.

StreamHub UI Docker


Features

  • Unified search across movieffm.net, 777tv.ai, and dramasq.io in one query
  • Three providers — movieffm & 777tv (movies + TV), dramasq (TV dramas, multiple CDN sources per episode)
  • Strict stream validation — checks HTTP status and reads m3u8 content (#EXTM3U + segment tags); HTML error pages no longer pass as valid
  • In-browser HLS playback via hls.js, with automatic fallback to the server proxy if direct play fails
  • m3u8 proxy that rewrites segment and #EXT-X-KEY URLs through the backend to bypass CORS and hotlinking
  • Poster proxy to bypass hotlink protection on cover images
  • LRU caching for search results, detail pages, stream checks, and media-type detection
  • Fast search timeouts — search requests time out at 8 s (configurable), detail/stream fetches at 20 s; slow providers never block fast ones
  • Traditional Chinese / English UI, language switch does not interrupt playback

Quick Start

Docker (recommended)

cp .env.example .env
# JWT_SECRET and ADMIN_PASSWORD are required — the server refuses to start
# without them. See the comments in .env.example.
docker compose up --build

Behind a reverse proxy on a public domain, set PUBLIC_DOMAIN to match (nginx allows CORS for that origin only) and make sure the proxy forwards WebSocket upgrades — /api/realtime is one.

Service URL
Frontend http://localhost:8080
Backend http://localhost:8787/api/health

Local Dev

# Backend (auto-reloads on file change)
cd server && npm install && npm run dev

# Frontend (Vite HMR)
cd frontend && npm install && npm run dev
# → http://localhost:5173  (proxies /api to localhost:8787)

Architecture

browser
  └── React SPA (Vite)
        └── /api/*  ──►  Express server
                            ├── /api/search        scrape & cache search results
                            ├── /api/item          scrape detail page (streams / seasons / episodes)
                            ├── /api/episodes      episode list for a season URL
                            ├── /api/sources       check & filter streams for one episode
                            ├── /api/check-sources batch check raw stream list (movies)
                            ├── /api/stream        HLS proxy + m3u8 URL rewriting
                            └── /api/poster        image proxy

Backend (server/)

File Role
src/index.js Express routes
src/stream.js Stream checker, HLS proxy, poster proxy
src/cache.js Four LRU caches (search 5 min, detail 10 min, streamCheck 3 min, mediaType 10 min)
src/providers/movieffm.js Scraper for movieffm.net
src/providers/seventv.js Scraper for 777tv.ai
src/providers/dramasq.js Scraper for dramasq.io (TV only, uses /drq/ JSON API for streams)
src/providers/index.js Provider registry
src/utils/http.js Shared fetchText / fetchJson with browser UA

Adding a provider: implement { search, getItem, getEpisodes, getEpisodeStreams } and register it in src/providers/index.js.

Frontend (frontend/src/)

Single App.jsx component. UI flow:

  1. Search → grouped poster grid per provider (skeleton shimmer while loading); each provider resolves independently
  2. Click poster → detail panel opens (poster + title on left, player on right)
  3. Select season → episode list loads
  4. Select episode → sources checked and listed as compact pills (green dot = direct, orange = proxy)
  5. Source selected → HLS plays; on fatal error auto-falls back to proxy URL

Native clients (android/, ios/)

Sideloaded phone and TV clients that talk to the same Express API — pure clients, signing in with user credentials only, with the admin console staying on the web.

Directory Contents
android/ One Gradle project: :core data layer, :mobile phone UI, :tv Android TV UI. Builds two APKs; UI is still a placeholder
ios/ One Xcode project, one target, adaptive for iPhone and iPad — not created yet
shared/api/ API behaviour notes every client has to get right

Each directory has a README covering its module layout, signing and design rules. Both are excluded from the Docker build context, since neither image consumes them.


Providers

Provider Movies TV Stream method
movieffm Scrapes embedded JSON from detail/episode pages
777tv Scrapes var player_* JSON from play pages
dramasq /drq/{id}/{ep} JSON API returns multiple CDN sources

PoC Scripts

Standalone CLI tools in PoC/ for scraping without the web UI:

pip install requests beautifulsoup4

python3 PoC/movieffm_cli.py
python3 PoC/777tv_cli.py
python3 PoC/dramasq_cli.py

All scripts apply the same strict m3u8 validation as the backend (reads first 4 KB, checks #EXTM3U + segment tags).


Requirements

  • Docker ≥ 26 — for the compose setup
  • Node.js ≥ 22 — for local dev
  • Python ≥ 3.11 + requests + beautifulsoup4 — for the PoC scripts only

About

Unified movie/TV search and HLS playback app aggregating movieffm and 777tv providers

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages