A fully self-hosted Stremio addon with 22+ torrent providers, 8 debrid services, Torznab/Jackett/Prowlarr integration, and TMDB recommendations.
No external scraper dependency. No third-party backend. Your API keys never leave your server.
magnetio.peterdsp.dev | Configure and Install
Magnetio is an open-source, self-hostable Stremio addon that comes with its own built-in torrent scraper. It queries 22 torrent providers in parallel (including Torznab-compatible indexers via Jackett or Prowlarr), deduplicates results, and optionally resolves them into instant direct-download streams through your debrid service of choice.
Everything runs on your own hardware (a Raspberry Pi is enough). No cloud subscriptions, no external scraper APIs, no data leaving your network.
| Magnetio | Typical Stremio addons | |
|---|---|---|
| Fully in-house scraping | Yes | Depends on external APIs |
| Self-hosted, private | Yes | Often cloud-hosted |
| 22 torrent providers + Torznab | Yes | Varies |
| Jackett / Prowlarr support | Yes | Rare |
| 8 debrid services | Yes | 1-3 typically |
| Background prewarm | Yes | No |
| Per-user config (providers, quality, language) | Yes | Limited |
| Subtitle sync pipeline | Yes | No |
| Redis caching with stale-while-revalidate | Yes | Basic or none |
| Prometheus metrics | Yes | Rare |
| Docker Compose one-command deploy | Yes | Varies |
You open a movie in Stremio
|
v
+---------------------------------+
| Magnetio Addon (:7000) |
| Receives stream/catalog/meta |
| request from Stremio client |
+---------------------------------+
|
Calls internal scraper
|
v
+---------------------------------+
| Magnetio Scraper (:8080) |
| Queries up to 21 providers |
| in parallel (max 4 concurrent) |
| 22s timeout per provider |
+---------------------------------+
|
Deduplicates by infoHash (keeps
highest-seeder entry per hash)
|
Content-filters results against
the actual requested title/season
|
v
+---------------------------------+
| Back to Addon |
| Applies quality/language/size |
| filters from user config |
| Sorts by chosen strategy |
+---------------------------------+
|
If debrid keys present:
check instant availability
on each configured service
|
+---------+---------+
| |
Cached Not cached
Resolve to Keep as P2P
direct HTTP magnet fallback
stream URL (or prewarm it)
| |
+---------+---------+
|
v
Return sorted stream list
to Stremio for playback
When a torrent is already cached on your debrid service, Stremio plays it as a direct HTTP stream at full speed. No buffering, no seeding wait, no port forwarding.
Magnetio ships with 22 providers covering movies, TV series, and anime, plus Torznab support for connecting external indexer managers.
| Provider | ID | Content | Method |
|---|---|---|---|
| YTS | yts |
Movies only | JSON API |
| EZTV | eztv |
Series only | JSON API |
| The Pirate Bay | thepiratebay |
Movies, Series | JSON API (apibay.org) |
| TorrentGalaxy | torrentgalaxy |
Movies, Series | HTML scraper |
| 1337x | leetx |
Movies, Series | HTML scraper (detail pages) |
| KickassTorrents | kickasstorrents |
Movies, Series | HTML scraper |
| LimeTorrents | limetorrents |
Movies, Series | HTML scraper |
| Bitsearch | bitsearch |
Movies, Series | HTML scraper |
| BT4G | bt4g |
Movies, Series | HTML scraper |
| BTDig | btdig |
Movies, Series | HTML scraper |
| GloTorrents | glotorrents |
Movies, Series | HTML scraper |
| TorLock | torlock |
Movies, Series | HTML scraper |
| TorrentDownloads | torrentdownloads |
Movies, Series | HTML scraper |
| TheRarBG | therarbg |
Movies, Series | HTML scraper (RARBG successor) |
| Rutor | rutor |
Movies, Series | HTML scraper (Russian) |
| Rutracker | rutracker |
Movies, Series | HTML scraper (Russian) |
| Provider | ID | Method |
|---|---|---|
| Nyaa | nyaa |
Atom RSS feed |
| AnimeSaturn | animesaturn |
HTML scraper (Italian) |
| SubsPlease | subsplease |
JSON API (fansubs) |
| AnimeTosho | animetosho |
RSS feed (aggregator) |
| nekoBT | nekobt |
Torznab API (fansubs) |
| Provider | ID | Method |
|---|---|---|
| Torznab | torznab |
Torznab XML API (any compatible endpoint) |
The Torznab provider is a universal connector that works with any Torznab-compatible indexer manager. Configure the API URL and key on the configure page. Magnetio will search all indexers you have set up in your Jackett or Prowlarr instance.
- Jackett - translates queries to 500+ tracker-specific requests. Free, open-source (MIT).
- Prowlarr - newer indexer manager with tighter *arr integration. Free, open-source (GPL-3.0).
Both are available as optional Docker Compose services (see Quick Start).
All providers run in parallel with a concurrency limit of 4 and a 22-second timeout. Results are deduplicated by infoHash, keeping the entry with the highest seeder count.
Debrid services cache torrents server-side and serve them as direct HTTP links, giving you instant, full-speed streams with no seeding required.
| Service | Code | Cache Check | Catalog | Prewarm |
|---|---|---|---|---|
| Real-Debrid | RD |
Yes | Yes | Yes |
| Premiumize | PM |
Yes | Yes | No |
| AllDebrid | AD |
Yes | No | Yes |
| DebridLink | DL |
No | Yes | Yes |
| EasyDebrid | ED |
Yes | No | No |
| Offcloud | OC |
No | No | Yes |
| TorBox | TB |
Yes | Yes | Yes |
| Put.io | PU |
No | Yes | Yes |
You can configure multiple debrid services simultaneously. Each one is checked independently for cached content.
git clone https://github.com/peterdsp/Magnetio.git
cd Magnetio
# Start all three services (scraper + addon + redis)
docker compose up -d
# Optional: include Jackett for 500+ additional indexers
docker compose --profile jackett up -d
# Optional: include Prowlarr instead (or alongside)
docker compose --profile prowlarr up -d
# Open in browser
open http://localhost:7000That is it. The addon runs on port 7000, the scraper on 8080, and Redis on 6379. Jackett runs on 9117 and Prowlarr on 9696 (both optional). All services share a Docker bridge network.
Terminal 1 (Scraper):
cd scraper
npm install
cp .env.example .env # edit if needed
node index.js # listens on :8080Terminal 2 (Addon):
cd addon
npm install
cp .env.example .env # set SCRAPER_URL=http://localhost:8080
node index.js # listens on :7000Open http://localhost:7000 to access the configuration page.
Navigate to http://your-server:7000 in a browser. The configuration page lets you:
- Set quality filters (4K, 1080p, 720p, 480p, CAM)
- Set language preferences for streams and subtitles
- Connect Torznab indexers (Jackett, Prowlarr, or any Torznab endpoint)
- Enter debrid API keys (with show/hide toggle)
- Configure sort order and result limits
- Enable or disable background prewarm
- Copy the manifest URL or click Install in Stremio
The generated URL encodes your preferences in a pipe-delimited config string that becomes part of the manifest path. No server-side storage of user settings.
https://your-server:7000/providers=yts,eztv,1337x|sort=qualityseeders|limit=10|RD=YOUR_KEY/manifest.json
| Parameter | Values | Default | Description |
|---|---|---|---|
providers |
Comma-separated provider IDs | All 21 | Which torrent providers to query |
sort |
qualityseeders, qualitysize, seeders, size |
qualityseeders |
How to rank streams |
limit |
1 to 50 |
10 |
Max streams returned per request |
qualities |
4k, 1080p, 720p, 480p, cam |
All | Quality whitelist |
languages |
ISO codes (en, es, pt, fr, de, it, ja, ru, ...) |
All | Stream language filter |
subtitleLanguages |
ISO codes | en |
Subtitle language preference |
torznabUrl |
Full Torznab API URL | - | Torznab endpoint (Jackett/Prowlarr) |
torznabKey |
API key | - | Torznab API key |
prewarm |
1, 0, true, false |
1 |
Background-add top uncached torrents to debrid |
prewarmLimit |
0 to 10 |
3 |
How many uncached results to prewarm per service |
excludeSizes |
Size thresholds like 1GB,2GB |
None | Exclude streams below these sizes |
maxSize |
Bytes | None | Maximum file size |
RD |
API key | - | Real-Debrid |
PM |
API key | - | Premiumize |
AD |
API key | - | AllDebrid |
DL |
API key | - | DebridLink |
ED |
API key | - | EasyDebrid |
OC |
API key | - | Offcloud |
TB |
API key | - | TorBox |
PU |
API key | - | Put.io |
Quick-start configurations for common use cases:
| Preset | What it does |
|---|---|
lite |
English-only, no CAM/screener, 3 providers, limit 5 |
brazuca |
Portuguese-focused, 4 providers, limit 10 |
Use a preset: https://your-server:7000/lite/manifest.json
Magnetio is a three-service stack, each with a clear responsibility:
magnetio/
|
| docker-compose.yml # Orchestrates all three services
|
+-- scraper/ # Torrent scraper backend
| | index.js # Express server (:8080)
| | package.json
| +-- lib/
| | | cache.js # Redis/in-memory cache (Keyv)
| | | catalog.js # Cinemeta top-content fetcher for prewarm
| | | cinemeta.js # IMDb ID to title/year/season/episode resolver
| | | cron.js # Scheduled prewarm job (node-cron)
| | | httpClient.js # Throttled Axios client with retries (Bottleneck)
| | | logger.js # Winston structured logging
| | | magnetHelper.js # Shared infoHash extraction, base32, size parsing
| | | prewarm.js # Prewarm orchestrator (scrapes top content into cache)
| | +-- titleHelper.js # Quality/codec/source/language/HDR parser
| +-- providers/
| | index.js # Parallel aggregator, deduplication, content filter
| | yts.js # ...21 built-in provider modules
| | torznab.js # Universal Torznab provider (Jackett/Prowlarr)
| +-- ...
|
+-- addon/ # Stremio addon frontend
| | index.js # Express server (:7000) + Prometheus metrics
| | serverless.js # Stremio SDK router + configure + subtitle proxy
| | addon.js # Stremio resource handlers (stream/catalog/meta/subtitles)
| | package.json
| +-- lib/
| | | manifest.js # Dynamic Stremio manifest generation
| | | configuration.js # Config URL parser + presets
| | | repository.js # HTTP client to call the scraper service
| | | sort.js # Quality-tiered stream sorting
| | | filter.js # Quality/language/size stream filtering
| | | streamInfo.js # Torrent record to Stremio stream object mapper
| | | subtitles.js # OpenSubtitles search integration
| | | subtitleProxy.js # Subtitle download + sync pipeline
| | | cache.js # Redis/in-memory cache (Keyv)
| | | languages.js # Language codes, names, flag emojis
| | | magnetHelper.js # Best-tracker list + magnet URI builder
| | | namedQueue.js # Request deduplication (prevents duplicate in-flight)
| | | landingTemplate.js # HTML/CSS/JS for the visual config page
| | | types.js # Shared enums and type definitions
| | +-- logger.js # Winston structured logging
| +-- moch/ # Debrid service integrations
| | moch.js # Debrid orchestrator (cache check + resolve)
| | mochHelper.js # Shared utils, per-key blacklisting
| | options.js # Debrid service registry
| | static.js # Static stream injections
| | realdebrid.js # Real-Debrid API client
| | premiumize.js # Premiumize API client
| | alldebrid.js # AllDebrid API client
| | debridlink.js # DebridLink API client
| | easydebrid.js # EasyDebrid API client
| | offcloud.js # Offcloud API client
| | torbox.js # TorBox API client
| +-- putio.js # Put.io API client
|
+-- .github/workflows/
+-- deploy.yml # CI/CD: validate, test, deploy via GitHub Actions
+------------------+ +-------------------+ +--------+
| Stremio Client | ------> | Addon (:7000) | ------> | Redis |
| (your TV/phone) | HTTP | stream/catalog | cache | (:6379)|
+------------------+ | debrid resolve | <------ +--------+
+--------+----------+ ^
| |
| HTTP :8080 |
v |
+-------------------+ |
| Scraper (:8080) | ------------>+
| provider queries | cache
| dedup + filter |
+-------------------+
| Method | Path | Description |
|---|---|---|
GET |
/ |
Visual configuration page |
GET |
/configure |
Stremio configuration endpoint |
GET |
/manifest.json |
Root addon manifest (default config) |
GET |
/:config/manifest.json |
User-configured addon manifest |
GET |
/:config/stream/:type/:id.json |
Stream results for a title |
GET |
/:config/catalog/:type/:id.json |
Debrid catalog (library browsing) |
GET |
/:config/meta/:type/:id.json |
Title metadata |
GET |
/:config/subtitles/:type/:id.json |
Subtitle results |
GET |
/proxy/subtitle/:id.srt |
Subtitle proxy with optional sync |
GET |
/health |
Health check ({ status: "ok" }) |
GET |
/stats |
Analytics dashboard (request counts, unique users) |
GET |
/swagger |
Prometheus metrics UI (auth required) |
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/providers |
List all available provider IDs and names |
GET |
/streams/:type/:id |
Scrape all providers for a title |
GET |
/streams/:type/:id?providers=yts,eztv |
Scrape specific providers only |
POST |
/prewarm |
Manually trigger cache prewarm |
GET |
/prewarm/status |
Check prewarm job status |
Each torrent result from the scraper follows this structure:
{
"infoHash": "a1b2c3d4e5f6...",
"title": "Movie.Name.2024.1080p.BluRay.x264-GROUP",
"seeders": 248,
"leechers": 12,
"size": 8589934592,
"provider": "1337x",
"quality": "1080p",
"codec": "AVC",
"source": "BluRay",
"languages": ["en"],
"hdr": null,
"imdbId": "tt1234567"
}Both services use Keyv backed by Redis (falls back to in-memory if Redis is unavailable).
| What | TTL | Notes |
|---|---|---|
| Scraper stream results | 1 hour | Per title, deduplicated |
| Addon stream responses | 1 hour | Stale-while-revalidate: 1h, stale-on-error: 4h |
| Empty results | Never cached | Prevents cache poisoning from transient failures |
| Prewarm scraper cache | 4 hours | Pre-populated by scheduled job |
| Debrid prewarm flags | 6 hours | Prevents re-adding already-prewarmed torrents |
| Addon router instances | 5 min | LRU with max 64 entries |
| Subtitle proxy cache | 1 hour | Per stream-specific subtitle |
Magnetio can proactively warm the cache and your debrid accounts:
- Scraper prewarm: A cron job (default: daily at 4 AM) fetches the top 50 movies and 20 series from Cinemeta, scrapes all providers for each, and stores results in Redis. When a user later requests one of these titles, the response is instant.
- Debrid prewarm: After filtering and sorting streams for a user request, Magnetio background-adds the top uncached torrents (configurable, default 3) to your debrid account. This is non-blocking. By the time you click play, the torrent may already be downloading or fully cached.
For debrid/direct HTTP streams, Magnetio can serve stream-specific subtitles:
- Fingerprints the media file (filename, size, OpenSubtitles hash via byte-range)
- Searches OpenSubtitles for the best match
- Downloads the subtitle
- Optionally runs
ffsubsync(audio-based alignment) oralass(split/framerate correction) - Caches and serves the corrected
.srt
This works reliably for debrid streams where the addon has access to the final HTTP URL.
The scraper validates that returned torrents actually match the requested content:
- For movies: title must contain at least part of the movie name
- For series: title must contain a matching season/episode marker (S01E02, 1x02, "Season 1", etc.)
- Word matching with a 50% threshold for multi-word titles
- Prevents unrelated results from polluting the stream list
Redis-backed, best-effort usage tracking:
- Daily request counts and per-type breakdowns (stream, catalog, subtitle, page views)
- Unique users via HyperLogLog (privacy-preserving, no PII stored)
- 7-day rolling history
- Available at
/stats
A NamedQueue system prevents duplicate in-flight requests. If 10 users request the same movie at the same instant, the scraper runs once and all 10 get the same result.
# Clone and configure
git clone https://github.com/peterdsp/Magnetio.git
cd Magnetio
cp .env.example .env
# Edit .env with your settings (at minimum):
# ADDON_PUBLIC_URL=https://your-domain.com
# METRICS_PASSWORD=your-secure-password
# Launch
docker compose up -dThe included workflow (.github/workflows/deploy.yml) handles automated deployment:
- Validate:
npm ci+npm teston Node 22 - Deploy:
rsyncto your server, preserving.envfiles - Build:
docker compose up -d --build --remove-orphanson the target - Health check: Optional ping to your
/healthendpoint
The workflow runs on a self-hosted GitHub Actions runner. Push to main triggers automatic deployment.
Stremio requires HTTPS for addon URLs. Common approaches:
- Cloudflare Tunnel or Cloudflare DNS proxy pointing to your server
- Nginx reverse proxy with Let's Encrypt SSL
- Tailscale or WireGuard for private access
The ADDON_PUBLIC_URL environment variable controls what base URL appears in manifests. The landing page uses location.origin which automatically resolves to your public domain when accessed through it.
| Variable | Default | Description |
|---|---|---|
PORT |
7000 |
HTTP port |
REDIS_URI |
In-memory | Redis connection string |
SCRAPER_URL |
http://localhost:8080 |
Internal scraper service URL |
ADDON_PUBLIC_URL |
Auto-detected | Public URL for manifest and subtitle links |
METRICS_USER |
admin |
Username for /swagger metrics |
METRICS_PASSWORD |
magnetio |
Password for /swagger metrics |
OPENSUBTITLES_API_KEY |
- | Enables subtitle resource |
OPENSUBTITLES_USERNAME |
- | OpenSubtitles account (for downloads) |
OPENSUBTITLES_PASSWORD |
- | OpenSubtitles account password |
OPENSUBTITLES_USER_AGENT |
Magnetio v1.0.0 |
User-Agent for OpenSubtitles API |
FFSUBSYNC_PATH |
Auto-detected | Path to ffsubsync binary |
ALASS_PATH |
Auto-detected | Path to alass binary |
SUBTITLE_SYNC_MAX_OFFSET_SECONDS |
300 |
Max offset for ffsubsync |
ALASS_SPLIT_PENALTY |
10 |
Split penalty for alass |
LOG_LEVEL |
info |
Winston log level |
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP port |
REDIS_URI |
In-memory | Redis connection string |
CACHE_TTL_STREAMS |
3600 |
Stream result cache TTL (seconds) |
PREWARM_CRON |
0 4 * * * |
Cron schedule for prewarm job |
PREWARM_MOVIES |
50 |
Number of top movies to prewarm |
PREWARM_SERIES |
20 |
Number of top series to prewarm |
LOG_LEVEL |
info |
Winston log level |
| Variable | Default | Description |
|---|---|---|
JACKETT_PORT |
9117 |
Exposed port for Jackett UI (profile: jackett) |
PROWLARR_PORT |
9696 |
Exposed port for Prowlarr UI (profile: prowlarr) |
TZ |
Etc/UTC |
Timezone for Jackett/Prowlarr containers |
Start optional services with Docker Compose profiles:
docker compose --profile jackett up -d # Jackett only
docker compose --profile prowlarr up -d # Prowlarr only
docker compose --profile jackett --profile prowlarr up -d # Both| Layer | Technology |
|---|---|
| Runtime | Node.js >= 18 (CI runs on 22) |
| Module system | ES Modules throughout |
| HTTP framework | Express 4 |
| Stremio integration | stremio-addon-sdk |
| HTML parsing | Cheerio |
| HTTP client | Axios |
| Rate limiting | Bottleneck (scraper), p-limit + p-queue (addon) |
| Caching | Redis 7 Alpine via Keyv |
| Monitoring | swagger-stats + prom-client (Prometheus) |
| Scheduling | node-cron |
| Logging | Winston |
| Subtitle sync | ffsubsync, alass (optional) |
| Containerization | Docker Compose v3.9 |
| CI/CD | GitHub Actions (self-hosted runner) |
# Start Redis (or use in-memory fallback)
docker run -d --name redis -p 6379:6379 redis:7-alpine
# Terminal 1: Scraper
cd scraper && npm install && npm run dev
# Terminal 2: Addon
cd addon && npm install && npm run devcd addon && npm testMagnetio does not host, store, or distribute any copyrighted content. It aggregates publicly available metadata (torrent hashes, magnet links) from third-party indexers. Users are solely responsible for complying with copyright laws in their jurisdiction.
Debrid service integrations are convenience features. API keys are passed through configuration URLs and are never stored server-side beyond the caching TTL.