# DebridStream Deep Architecture (Reverse-Engineered from v3.3.1 APK)

> **Source:** Decompiled DebridStream FireTV APK v3.3.1 (`/tmp/firetv-jadx/`)
> **Date:** May 2026
> **Key finding:** DebridStream has **zero hardcoded addon URLs**. All addon configs come from Firebase Firestore per-user documents.

## Firebase Data Model

### Collections
| Collection | Purpose | Document Key |
|-----------|---------|--------------|
| `addOns` | User's addon list (array of manifest URLs) | User ID |
| `accountSync` | Profile sync data (watch history, progress) | User ID |
| `catalogs` | Catalog/preferences data | User ID |
| `debridKeys` | Debrid provider tokens | User ID |

### addOns Document Format
Each user's document in `addOns` collection stores an array of **manifest URLs** (not stream URLs directly):

```json
{
  "addOns": [
    "https://some-config-host.com/addons.json",
    "https://another-host.com/my-addons.json"
  ]
}
```

Alternative field names tried in order: `addOns`, `addons`, `addonUrls`, `addon_urls`, `AddOns`.

## Addon Loading Pipeline

### Step 1: Fetch Manifest URLs
`W2/z3.a()` iterates the URL array, calls `m()` which does an HTTP GET on each URL.

### Step 2: Parse Response
`W2/z3.r()` parses the JSON response:
- If response is a JSON array → use directly
- If response is a JSON object with `"data"` field → use that
- If response is a single object → wrap in array

Each item in the parsed array is classified by its `type` field:
- `"reg_hash"` → **registered addon** (needs backend proxy)
- anything else (e.g. `"json_imdb"`) → **external addon** (config-driven)

### Step 3: Build Addon Configs
`W2/z3.k(list, list2)` builds `ScraperAddon` (U2.c) objects from both lists.

## Addon Configuration Format (External / json_imdb)

Each addon in the JSON array must include:

```json
{
  "name": "My Addon",
  "type": "json_imdb",
  "url": "https://example.com/stream/%searchPattern.json",
  "jsonResultsKey": "streams",
  "itemType": "info_hash",
  "httpUrlTargetKey": "url",
  "sizeAttr": "behaviorHints.videoSize",
  "sizePattern": null,
  "torrentNameTargetKey": "title",
  "debridProvider": "realdebrid",
  "searchPattern": {
    "movie": "movie/%s",
    "tv": "series/%s:%s:%s"
  }
}
```

### Required Fields (validated in W2/z3.d())
| Field | Condition | Notes |
|-------|-----------|-------|
| `name` | Required | Display name |
| `type` | Required | `"json_imdb"` or `"reg_hash"` |
| `url` | Required, must be `https://`, must contain `%searchPattern` | URL template |
| `itemType` | Required | `"info_hash"` or `"http_url"` |
| `jsonResultsKey` | Required, non-empty | JSON field to extract results from (default: `"streams"`) |
| `httpUrlTargetKey` | Required if `itemType == "http_url"` | Field containing direct URL |
| `searchPattern` | Required, must have both `movie` and `tv` | How to format IMDb IDs |

### Optional Fields
| Field | Purpose |
|-------|---------|
| `sizeAttr` | Dot-notation path to file size (e.g. `"behaviorHints.videoSize"`) |
| `sizePattern` | Optional regex for extracting size from string |
| `torrentNameTargetKey` | Dot-notation path to torrent/release name |
| `debridProvider` | If set, only route to this provider; if null, check all connected |
| `registeredDebridProvider` | Alternative field for the above |

## Registered Addon Flow (type: reg_hash)

Registered addons use DebridStream's own backend as a proxy:

1. **Build config JSON** via `W2/z3.f(provider, token)`:
   ```json
   {
     "streaming_providers": [{"name": "Provider", "service": "realdebrid", "token": "TOKEN"}],
     "selected_resolutions": ["4k", "2160p", "1440p", "1080p", "720p", ...],
     "max_streams": 25,
     "enable_catalogs": true,
     "quality_filter": ["BluRay/UHD", "WEB/HD", ...],
     "language_sorting": ["English", "Tamil", ...],
     "stream_type_grouping": "separate",
     "torrent_sorting_priority": [{"name": "cached", "direction": "desc"}, ...]
   }
   ```

2. **Encrypt config via POST** to `registerUrl`:
   ```
   POST {registerUrl}
   Content-Type: application/json
   Body: {config JSON}
   Response: {"status": "success", "encrypted_str": "base64encrypteddata..."}
   ```

3. **Build stream URL**:
   ```
   {baseUrl}/{mode}/{encrypted_str}/stream/%searchPattern.json
   ```
   Where `mode` is from the addon config (e.g. `"encrypt-user-data"`).

## Full Scraping Pipeline (N2.q)

```
ScraperAddon[] (from step 2/3 above)
  │
  ├─ For each addon:
  │     URL = addon.url.replace("%searchPattern", "movie/tt1234567")
  │     via U2.e → HTTP GET → response body
  │     via U2.f.a() → parse using config keys:
  │       - Extract array from jsonResultsKey field
  │       - For each item:
  │         - itemType == "info_hash": extract infoHash, title, size
  │         - itemType == "http_url": extract direct URL from httpUrlTargetKey
  │       → List<ScraperStreamItem> (infoHash, directUrl, title, behaviorHints)
  │
  ├─ N2.i (result handler):
  │     Filters by enabled providers set
  │     Deduplicates by hash
  │     → N2.q.dispatch(provider, links)
  │
  ├─ N2.q.e() (debrid dispatch):
  │     Routes each link to provider-specific resolver:
  │     - realdebrid → w class (API: /unrestrict/link, /torrents/addMagnet)
  │     - torbox → V2.n (API: /api/torrents/createtorrent, /api/torrents/requestdl)
  │     - offcloud → A4.g
  │     - alldebrid → AbstractC0823a
  │     - debrider → L4.a
  │     - premiumize → support.v4.media.session.b
  │
  └─ N2.e (CachedLinkResult):
        Quality enrichment from filename
        Flags: 4K, FHD, HD, REMUX, HEVC, Atmos, TrueHD, HDR, DV P5, DV P7, DTSHD, AV1, 3D, CAM, Sample
```

## Quality Detection (C1125i / ScraperQualityDetector)

19 regex patterns detect quality from filenames:
- Resolution: 4K/2160p, 1080p, 720p
- Quality: REMUX, CAM, Sample
- Codec: HEVC, AV1
- Audio: Atmos, TrueHD, DTSHD
- Visual: HDR, HDR10+, DV P5, DV P7, DV, 3D, AI Upscale

## Debrid Provider Priority Ranking (C1125i.a())

| Provider | Priority Score |
|----------|---------------|
| realdebrid | 101 |
| alldebrid | 100 |
| premiumize | 50+ |
| torbox | 1 |
| offcloud | 2 |
| debrider | 3 |

Higher = preferred for resolution when multiple providers have the same hash cached.

## Empirical Test Results (May 2026)

Tested all 6 default addon URLs with `movie/tt0109830` (Forrest Gump):

| Addon | HTTP | Streams | infoHash | Verdict |
|-------|------|---------|----------|---------|
| Torrentio (no tokens) | 200 | **50** | ✅ All 50 | **WORKS** |
| AIOStreams elfhosted | 200 | 1 placeholder | ❌ | Needs config |
| Comet elfhosted | 403 | — | — | Blocked |
| MediaFusion elfhosted | 200 | 0 | — | Empty |
| Jackettio elfhosted | 200 | 1 placeholder | ❌ | Needs config |
| PeerFlix elfhosted | 404 | — | — | Dead |

**Key finding:** Only Torrentio's public endpoint returns usable infoHashes without configuration. All elfhosted addons require debrid token setup to return results.

**Torrentio response format (no tokens):**
```json
{
  "streams": [
    {
      "name": "Torrentio\n4k DV | HDR",
      "title": "Forrest.Gump.1994.2160p.BluRay.REMUX.DV.P7.HDR.MULTi.TrueHD.Atmos.7.1.H265-BTM\n👤 43 💾 85.48 GB ⚙️ ThePirateBay\nMulti Audio",
      "infoHash": "94467188b95161902bd9...",
      "fileIdx": 0,
      "behaviorHints": {}
    }
  ]
}
```

Note: `infoHash` is always populated. `url` is never present (no tokens → no playable URLs). `behaviorHints.videoSize` is NOT present — size is embedded in the `title` text.

## Hardcoded API Endpoints Found

These are compiled into the app (not from Firestore):

| URL | Purpose |
|-----|---------|
| `https://api.real-debrid.com/rest/1.0/` | Real-Debrid API |
| `https://api.alldebrid.com/v4/` | AllDebrid API |
| `https://www.premiumize.me/api/` | Premiumize API |
| `https://api.torbox.app/v1/` | TorBox API |
| `https://debrider.app/api/v1/` | Debrider API |
| `https://v3-cinemeta.strem.io/` | Cinemeta metadata |
| `https://opensubtitles-v3.strem.io/` | OpenSubtitles |
| `https://api.trakt.tv/` | Trakt.tv |
| `https://api.themoviedb.org/3/` | TMDB API |
| `https://image.tmdb.org/t/p/` | TMDB images |

Debrider and Offcloud are not in our app yet.

## Cinemeta Metadata Enrichment

DebridStream uses `https://v3-cinemeta.strem.io/meta/{type}/{id}.json` for episode-level metadata enrichment (titles, posters, episode numbers, etc.). This is the official Stremio Cinemeta addon. The feature flag `use_cinemeta_episode_enrichment` controls whether this is active.

## Remote Config (GitHub) / Kill Switch
```
https://raw.githubusercontent.com/lawdev-cmd/map/refs/heads/main/config.json
```

Format:
```json
{
  "emergencyMessage": "",
  "tmdbTurnOffGzip": false,
  "filters": {
    "ALL": ["Ben The Men", "Ultra dox", "ColdFilm", "tagalog", ...],
    "RD": ["[rartv]", "[rarbg]", "[eztv]", "YTS", "WEB-DL", "AMZN", "DSNP", ...]
  }
}
```

This is a **kill switch** and **filter list** only — not an addon source. `ALL` filters are global title exclusions; `RD` filters are Real-Debrid-specific title exclusions (for files that 451 even when cached).

## Key Architectural Lessons

1. **No hardcoded addons** — Users configure their own addon URLs. The app is just the pipeline.
2. **Config-driven parsing** — Every aspect of how an addon response is parsed is configurable via the addon's JSON config (field keys, item type, size extraction).
3. **Two-tier addon model** — External (any Stremio-compatible URL) vs Registered (backend-proxied with encrypted debrid config).
4. **Debrid dispatch is centralized** — N2.q dispatches to 6 provider-specific resolvers, not per-addon. Addons return infoHashes, the router decides which debrid service to use.
5. **Quality enrichment is decoupled** — Happens AFTER debrid resolution, from the filename. Not from the addon response.
6. **SearchPattern is required** — Each addon must define both `searchPattern.movie` and `searchPattern.tv` to control how content IDs are formatted.
