# DebridStream FireTV — Source Scraping Architecture

Full trace of how DebridStream v3.3.1 discovers and resolves movie/TV sources, with comparison to the Stremio-protocol approach used by Unspooled.

## Overview

DebridStream uses **Pattern B** (custom API per scraper) architecture:
- Addon list loaded from **remote GitHub JSON config** (not compiled-in)
- Each addon has a **config-driven JSON parser** (knows which fields to extract)
- Parsed results are **routed by debrid provider** to dedicated API integration code
- No standard Stremio protocol anywhere in the pipeline

## Key Files (obfuscated names)

| Package | Class | Purpose |
|---------|-------|---------|
| `N2.c` | `N2.c` | Remote config loader: fetches `config.json` from GitHub, parses `filters.RD`/`filters.ALL` exclusions + addon list |
| `N2.q` | `N2.q` | **Central orchestrator** — the `l()` function drives the full scraping pipeline |
| `U2.c` | `ScraperAddon` | Addon model: `url`, `jsonResultsKey`, `name`, `sizeAttr`, `sizePattern`, `torrentNameTargetKey`, `httpUrlTargetKey`, `debridProvider` |
| `U2.e` | Coroutine worker | Makes HTTP GET to addon URL, parses response |
| `U2.f` | Response parser | Extracts streams using addon-specific field mapping from `ScraperAddon` config |
| `U2.g` | Result combiner | Merges results from multiple addon calls |
| `N2.e` | `CachedLinkResult` | Final resolved link model: hash, linkType, files, quality flags (4K,FHD,HD,Remux,HEVC,Atmos,HDR,DV,DTS,AV1...) |
| `N2.h` | `DownloadLinkResult` | Intermediate resolution result: download URL, name, size, files, status |
| `U2.a` | `BehaviorHints` | Stremio-compatible hints (videoSize, filename) |
| `f3/AbstractC1432a` | OkHttp interceptor | Adds auth headers for debrid domains, restricts protocol to HTTP/1.1 + H2 |
| `i` (in `g3`) | `StremioSubtitleMatch` | Subtitle matching from addon responses |

## Scraping Pipeline (step by step)

### 1. Remote Config Loading (`N2.c.b()`)

```java
// Fetches from:
https://raw.githubusercontent.com/lawdev-cmd/map/refs/heads/main/config.json
```

Config structure:
```json
{
  "filters": {
    "RD": ["excluded-name-patterns-for-real-debrid"],
    "ALL": ["global-exclusion-patterns"]
  },
  "tmdbTurnOffGzip": false,
  "emergencyMessage": "optional msg"
}
```

Stored in `N2.c.f5186a` (ArrayList of `ScraperAddon`). Also loads `entryMap.json` from same GitHub for TMDB↔IMDB overrides.

### 2. Search Initiation (`ScraperResultsViewModel.ensureStarted()`)

```java
// Takes imdbId + type ("movie" or "tv")
ScraperResultsViewModel.ensureStarted(imdbId, type)
  → N2.q.l(imdbId, type, options, activeAddons, filters, callback, cancelCallback, httpClient)
```

### 3. Orchestrator (`N2.q.l()`)

Builds path:
- Movie: `movie/{imdbId}` → `movie/tt1234567`
- TV:   `series/{imdbId}:{season}:{episode}` → `series/tt1234567:1:2`

For each `ScraperAddon` in the config:
- Replaces `%searchPattern` in `ScraperAddon.url` with the path
- Launches a coroutine via `U2.e` to make the HTTP GET

### 4. Addon Request (`U2.e.invokeSuspend()`)

```java
s sVar = new s(url, "GET", ...);  // HttpRequest model
a3 = httpClient.a(sVar, this);     // Makes the HTTP call
t tVar = (t) a3;                    // HttpResponse model (ok, statusCode, body)
```

Response parsed by `U2.f.a()` using:
- `cVar.f6888b` = `jsonResultsKey` (which JSON field holds the stream list)
- `cVar.f6891e` = `sizePattern` (regex for file size extraction)
- `cVar.f6892f` = `torrentNameTargetKey` (field for torrent/filename)
- `cVar.f6894h` = `httpUrlTargetKey` (field for direct HTTP URL)

### 5. Debrid Provider Routing (`N2.q.b()`)

Each parsed link is routed based on the addon's `debridProvider` field:

```java
switch (providerName) {
    case "realdebrid" → w.k()     // Resolve via RealDebrid API
    case "torbox"     → V2.n.i0() // TorBox API
    case "offcloud"   → A4.g.D()  // OffCloud API
    case "alldebrid"  → L()       // AllDebrid API
    case "debrider"   → L4.a.P()  // Debrider API
    case "premiumize" → b.G()     // Premiumize API
}
```

Each provider's integration:
1. Takes the magnet/torrent/infoHash from the addon response
2. Calls the provider's API to:
   - Check cache status
   - Unrestrict/uncache the link
   - Get direct download URL + filename + size
3. Returns a `DownloadLinkResult` (N2.h) with resolved URL, name, size, files

### 6. Result Enrichment (`N2.e`)

Each resolved link is tagged with quality flags parsed from filename:
- `is4K`, `isFHD`, `isHD` — resolution tiers
- `isRemux` — untouched Bluray
- `isHevc` — codec
- `isAtmos`, `isTrueHD` — audio
- `isHDR`, `isDVP5`, `isDVP7`, `isDV`, `isHDR10` — HDR/DolbyVision
- `isAV1` — next-gen codec
- `isCAM` — low-quality cam rip
- `isDTSHD` — DTS-HD audio
- `isSample` — short sample file

### 7. Cancellation Pattern

- `AtomicInteger activeRunId` — incremented on each new search
- Callbacks check `i6 != scraperResultsViewModel.activeRunId.get()` — if stale, drop result
- `currentCancel` — lambda to cancel in-flight requests

## Comparison: DebridStream vs Unspooled

| Aspect | DebridStream | Unspooled |
|--------|-------------|-----------|
| **Addon source** | Remote GitHub config (scraper list) | Built-in registry + Cloudflare Worker |
| **Protocol** | Custom API per scraper (config specifies parse keys) | Standard Stremio addon protocol |
| **Debrid integration** | Centralized router dispatches to 6 dedicated provider SDKs | Each provider self-contained (Torrentio embeds tokens in URL, AIOStreams has own integration) |
| **Response parsing** | Config-driven: `jsonResultsKey`, `sizeAttr`, `httpUrlTargetKey` | Fixed Stremio schema (url, infoHash, name, behaviorHints) |
| **Quality detection** | During debrid resolution from filename + file list | StreamFactExtractor with regex patterns from filename |
| **Parallelism** | CopyOnWriteArrayList + AtomicInteger counters | supervisorScope + async/awaitAll |
| **Caching** | Minimal in-memory (CachedLinkResult objects) | Multi-layer CacheManager (manifest, catalog, meta, stream) with per-resource TTLs |
| **Ranking** | Basic dedup + filter | 7-dimension scoring matrix with device capabilities, history, provider timeouts |
| **Remote kill switch** | ✅ GitHub config | ❌ |
| **Adaptive parsing** | ✅ Each addon configured independently | ❌ Must fit Stremio schema |
| **Stream dedup** | Simple (same link hash) | Multi-pass (URL, infoHash, smart hash, fuzzy filename) |

## Key Insights

1. **Two-layer architecture**: DebridStream cleanly separates addon/scraper fetching (layer 1) from debrid resolution (layer 2). The orchestrator (`N2.q`) handles both but routes through different provider-specific code for layer 2.

2. **Config-driven flexibility**: The entire scraping pipeline can be reconfigured without an app update by changing the GitHub config. New addons can be added, old ones removed, parse mappings changed — all OTA.

3. **Tradeoff**: Config-driven parsing is more flexible but requires knowing each addon's exact JSON shape. Stremio protocol is rigid but standardized — any of 1000+ existing Stremio addons work without config changes.

4. **If porting to Unspooled**: The DebridStream approach to per-debrid-provider SDK integration (dedicated API calls for unrestrict/check-cache/resolve) is more robust than embedding tokens in Torrentio URLs. Each provider has different ratelimit/error/response patterns that a dedicated class handles better than URL-param encoding.
