A self‑hostable, token‑based, privacy‑friendly IPTV addon for Stremio supporting:
- Direct M3U playlists (TV + Movie + heuristic Series detection)
- Xtream Codes API (JSON mode + m3u_plus mode)
- Panel XMLTV or custom EPG feeds
- Channel Logos, Live Now info, Upcoming programme snippets
- Movies & VOD catalog
- Series catalog (Xtream native + M3U heuristic grouping)
- Client pre‑flight validation with CORS bypass fallback
- Config token encoding (+ optional encryption)
- Local LRU + Redis caching
- Lightweight logo proxy & EPG parsing
- Graceful degradation (EPG failures do not block usage)
- Visit your hosted base URL (
https://your-host/
) - Pick a mode:
- “Direct M3U / EPG” → paste playlist + optional XMLTV
- “Xtream Codes API” → enter panel URL + credentials (or toggle m3u_plus)
- (Optional) Provide or override EPG source
- Pre‑flight runs:
- Fetch + parse playlist (client; server fallback if CORS)
- Fetch + quick-scan EPG (non-fatal)
- Build a configuration token
- A Stremio manifest URL appears (disabled buttons enable when ready):
https://your-host/<TOKEN>/manifest.json stremio://your-host/<TOKEN>/manifest.json
- Open in Stremio → catalogs appear:
- IPTV Channels (tv)
- IPTV Movies (movie)
- IPTV Series (series)
git clone https://github.com/Inside4ndroid/IPTV-Stremio-Addon.git
cd IPTV-Stremio-Addon
cp .env.example .env # create your env (or export vars manually)
npm install
npm start
# Server runs on PORT (default 7000)
open http://localhost:7000/
Minimal .env
:
PORT=7000
CACHE_ENABLED=true
CACHE_TTL_MS=21600000
MAX_CACHE_ENTRIES=300
DEBUG_MODE=true
# Optional:
# REDIS_URL=redis://localhost:6379
# CONFIG_SECRET=super-long-random-string (enables /encrypt)
# PREFETCH_ENABLED=true
# PREFETCH_MAX_BYTES=5000000
docker build -t stremio-iptv-addon .
docker run -d \
-e PORT=7000 \
-e DEBUG_MODE=false \
-e CACHE_ENABLED=true \
-p 7000:7000 \
--name stremio-addon \
stremio-iptv-addon
services:
redis:
image: redis:7-alpine
restart: unless-stopped
addon:
build: .
restart: unless-stopped
environment:
PORT: 7000
REDIS_URL: redis://redis:6379
CACHE_ENABLED: "true"
CACHE_TTL_MS: 21600000
MAX_CACHE_ENTRIES: 400
PREFETCH_ENABLED: "true"
PREFETCH_MAX_BYTES: 6000000
CONFIG_SECRET: "generate_a_long_random_string"
DEBUG_MODE: "false"
depends_on:
- redis
ports:
- "7000:7000"
Then open: http://localhost:7000/
Type | Format | Notes |
---|---|---|
Plain Token | Base64URL JSON (no prefix) | Generated by config UI |
Encrypted Token | enc:<ciphertext> |
Requires CONFIG_SECRET and /encrypt endpoint |
Manifest URL | https://host/<TOKEN>/manifest.json |
Supply to Stremio |
Stremio Protocol | stremio://host/<TOKEN>/manifest.json |
Auto-open from UI |
Decryption / parsing is done server-side before addon build.
Endpoint | Method | Description |
---|---|---|
/ |
GET | Landing + mode selection |
/configure-direct |
GET | Direct config page (no token) |
/configure-xtream |
GET | Xtream config page (no token) |
/:token/configure-direct |
GET | Reconfigure direct (pre-filled if token decodes) |
/:token/configure-xtream |
GET | Reconfigure Xtream |
/:token/manifest.json |
GET | Stremio manifest |
/:token/catalog/:type/:id/:extra?.json |
GET | Catalog resource (SDK handled) |
/:token/stream/:type/:id.json |
GET | Stream resource |
/:token/meta/:type/:id.json |
GET | Meta resource |
/:token/logo/:tvgId.png |
GET | Logo proxy (tries multiple sources) |
/api/prefetch |
POST | Server-side fetch (CORS bypass, size limited) |
/encrypt |
POST | Returns encrypted token (requires CONFIG_SECRET ) |
/health |
GET | Health probe (JSON) |
curl -X POST http://localhost:7000/api/prefetch \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com/playlist.m3u","purpose":"playlist"}'
Feature | Direct M3U | Xtream JSON | Xtream m3u_plus | Notes |
---|---|---|---|---|
Live Channels Catalog | ✅ | ✅ | ✅ | Unified tv catalog |
Movies Catalog | Heuristic (by title/year/group) | ✅ | ✅ | Filtering rules |
Series Catalog | Heuristic (SxxEyy / Season X) | Native get_series + get_series_info |
Heuristic | Per-episode videos |
EPG | XMLTV custom or provided | Panel xmltv.php or custom | Panel xmltv.php or custom | Offset supported |
Logos | tvg-logo / fallback proxy | Uses stream_icon / cover | tvg-logo where present | Multiple sources attempted |
CORS Bypass | Yes (prefetch) | Yes (prefetch) | Yes (prefetch) | Browser first, fallback server |
Encryption | Token-level | Token-level | Token-level | Optional |
Caching | LRU + optional Redis | Same | Same | Cache key = hashed config |
Series Episodes | Local heuristic grouping | On-demand per series (lazy) | Heuristic | Episode IDs = iptv_series_ep_* |
Variable | Default | Purpose |
---|---|---|
PORT |
7000 |
HTTP server port |
REDIS_URL |
unset | Enable Redis caching (interface + data) |
CACHE_ENABLED |
true |
Master toggle for LRU + Redis |
CACHE_TTL_MS |
21600000 (6h) |
TTL for cached data |
MAX_CACHE_ENTRIES |
300 |
LRU entry cap |
CONFIG_SECRET |
unset | Enables /encrypt endpoint for token encryption |
DEBUG_MODE |
false |
Enables verbose diagnostic logs |
PREFETCH_ENABLED |
true |
Enable server-side prefetch CORS bypass |
PREFETCH_MAX_BYTES |
5000000 |
Max bytes returned from /api/prefetch |
NODE_ENV |
(user value) | Standard Node semantics |
Redis is optional. Without it, only in‑process LRU is used (per container).
┌───────────────────────────┐
│ Browser Client │
│ (Direct/Xtream Config UI) │
└──────────┬────────────────┘
│ Pre-flight (fetch playlist & optional EPG)
▼
┌───────────────────────────┐
│ /api/prefetch │ ← CORS bypass, size-limited, SSRF guarded
└──────────┬────────────────┘
│ Token JSON
▼
┌───────────────────────────┐
│ server.js │
│ - decrypt (if enc:) │
│ - cache interface │
│ - createAddon(config) │
└──────────┬────────────────┘
│
▼
┌───────────────────────────┐
│ addon.js │
│ - load cache │
│ - fetch provider data │
│ - parse M3U / EPG │
│ - build catalogs │
└──────────┬────────────────┘
│ Stremio resource routes
▼
┌───────────────────────────┐
│ Stremio Client │
│ Catalog / Meta / Stream │
└───────────────────────────┘
- Fetches
get_series
- Per-series metadata lazily enriched via
get_series_info
- Each episode becomes a
video
in the series meta, streamable by ID
- Detects patterns:
S01E05
,S1E2
,Season 2 Episode 4
,Season 3 Ep 09
- Groups by base series name (title with season/episode suffix removed)
- Builds synthetic series entities with episodes list
- Missing season or episode → defaults to
season=1
,episode=0
Area | Current Defense | Recommendation |
---|---|---|
Prefetch SSRF | Blocks localhost & RFC1918 ranges | Optionally maintain allowlist or DNS resolve & IP classify |
Token Leakage | Long base64url token + optional encryption | Always use CONFIG_SECRET for shared public hosts |
EPG Size | Prefetch max bytes & server timeouts | Adjust PREFETCH_MAX_BYTES for very large XMLTV feeds |
DoS / Abuse | Basic size limits | Add rate limiting (e.g. express-rate-limit ) |
Sensitive Creds | Xtream credentials stored only in token | Encourage users not to share tokens publicly |
- Go to
/configure-direct
- Paste:
https://example.com/playlist.m3u
- (Optional) EPG:
https://example.com/guide.xml
- Copy manifest URL:
https://host/<TOKEN>/manifest.json
- Add to Stremio
- Base URL:
http://panel.example.com:8080
- Username / Password
- Leave “Use m3u_plus” unchecked
- Enable EPG (panel or custom)
- Install via generated manifest
- Tick “Use m3u_plus playlist”
- Optional output format:
ts
/hls
- EPG source choice + offset
- Install generated manifest
After configuration:
TOKEN=<paste-token>
HOST=http://localhost:7000
curl "$HOST/$TOKEN/manifest.json" | jq '.name,.version'
# TV catalog
curl "$HOST/$TOKEN/catalog/tv/iptv_channels.json" | jq '.metas[0]'
# Movie catalog search example
curl "$HOST/$TOKEN/catalog/movie/iptv_movies.json?search=action" | jq '.metas | length'
# Series meta (example ID)
curl "$HOST/$TOKEN/meta/series/iptv_series_<id>.json" | jq '.meta.videos[0]'
Mode | How |
---|---|
Enable debug globally | DEBUG_MODE=true |
Per-token debug | Check “Enable Debug Logging” in UI |
Inspect parsing | Console shows playlist size, entries, EPG programmes |
Timeout fallback | Buttons enable after build timeout to allow manual retry |
Layer | Scope | Contents |
---|---|---|
In-Memory LRU | Per process | Addon data (channels/movies/series/epg) |
Redis (optional) | Cross replicas | Same payload (JSON) + interface build marker |
Build Promise Cache | Prevents simultaneous duplicate warm builds |
Cache key = md5
of normalized config subset.
- Genre filtering optimization
- Optional transcode / proxy (HLS rewriting)
- Multi-EPG merge & channel mapping UI
- Webhook or schedule-based background refresh
- Token revocation list
- Light theme toggle + user theme persistence
- Add channel favorites (local storage layer)
Want to help? See Contributing below.
Q: The playlist fetch fails with a CORS error.
A: The browser first attempt failed; server /api/prefetch
will retry. Ensure PREFETCH_ENABLED=true
.
Q: EPG shows zero programmes.
A: The quick scan counts <programme>
tags only. If compressed or gzipped, ensure server delivers uncompressed or extend prefetch to decompress.
Q: Some logos missing.
A: The proxy tries multiple templates; contribute additional logo source patterns.
Q: Token feels huge.
A: It’s a compact base64url JSON; enable encryption if sharing.
Q: Series episodes missing (M3U).
A: Ensure naming matches patterns (S01E01
or Season 1 Episode 1
). Heuristic grouping cannot infer arbitrary naming.
- Fork & branch:
feat/your-feature
- Keep changes modular (UI / provider / core)
- Run lint/tests (add if expanding)
- Open PR with:
- Summary + reproduction steps
- Performance / memory notes if heavy parsing changes
- Screenshots (UI changes) preferred
- Prefer async/await over callbacks
- Avoid blocking large buffers (stream if >10MB future tasks)
- Keep provider logic separated (
providers/
) - Guard network operations with timeouts
Please include:
- Node version
- Hosting method (Docker / bare / serverless)
- Provider type (direct / xtream-json / xtream-m3u)
- Sample (sanitized) playlist or line count
- Logs with
DEBUG_MODE=true
(scrub credentials)
Create an issue: https://github.com/Inside4ndroid/IPTV-Stremio-Addon/issues
(Previous embedded image returned AccessDenied from BuyMeACoffee CDN on some networks / GitHub proxies.)
Use one of these reliable text/badge links instead:
Or link: https://buymeacoffee.com/K3QSoR2
This project does not provide IPTV content.
You are solely responsible for ensuring that playlists and streams you load are legal in your jurisdiction.
The authors are not liable for misuse.
MIT License (see LICENSE
file).
Attribution appreciated but not required.
A serverless.js
handler is included (experimental):
- Cold starts rebuild addon interface
- You must adapt dynamic token passing (currently static)
Kind | Pattern |
---|---|
Live Channel | `iptv_live_<stream_id |
Movie | `iptv_vod_<stream_id |
Series | `iptv_series_<series_id |
Episode | `iptv_series_ep_<episode_hash |
# 1. Start server with CONFIG_SECRET
# 2. POST JSON config you would otherwise encode
curl -X POST http://localhost:7000/encrypt \
-H 'Content-Type: application/json' \
-d '{
"provider":"direct",
"m3uUrl":"https://example.com/list.m3u",
"enableEpg":true,
"epgUrl":"https://example.com/epg.xml"
}'
# Response:
# { "token": "enc:..." }
# Manifest URL: https://host/enc:.../manifest.json
Symptom | Likely Cause | Action |
---|---|---|
Buttons never enable | Manifest build error | Check server logs (addon build), ensure playlist accessible |
502 on /api/prefetch |
Remote host blocked / TLS error | Try direct browser fetch or adjust server CA bundle |
High memory usage | Massive playlist & no Redis | Increase RAM or add Redis to share cache across restarts |
Missing search results | Stremio partial search | Use shorter, distinctive search terms; ensure case-insensitive |
EPG times off | Timezone difference | Set EPG Offset in config (+/- hours) |
Add new provider:
- Create
providers/myProvider.js
exportingfetchData(addonInstance)
and optionallyfetchSeriesInfo
. - Normalize items to:
{ id, name, type: tv|movie|series, url, poster/logo, attributes:{...} }
. - Update config UI to set
provider: 'myProvider'
. - Adjust
addon.js
logic if custom behavior needed.
Current UI theme mimics Stremio’s dark violet aesthetic:
- Accent gradient:
#7043ff → #c58cff
- Panels: layered deep navy/indigo
- Accessible contrast for logs/forms
- Responsive overlay with progress stripes
Feel free to PR:
- Alternate light mode
- High contrast accessibility mode
- User theme selector (localStorage)
Step | Done? |
---|---|
Playlist reachable via server & browser | ☐ |
EPG XML reachable (or disabled gracefully) | ☐ |
CONFIG_SECRET set (if sharing public) |
☐ |
Reverse proxy passes through paths | ☐ |
Optional HTTPS cert configured | ☐ |
Redis deployed (optional scaling) | ☐ |
Firewall restricts internal networks | ☐ |
Happy streaming!
For ideas, feature requests, or large refactors — open a discussion first so we can align on direction.
PRs welcome ❤️