# `Laev.Providers`
[🔗](https://github.com/alexdont/laev/blob/main/lib/laev/providers.ex#L1)

Multi-debrid orchestration: one resolve/probe interface over every
configured provider (Real-Debrid first — deepest cache — then TorBox).

A source is playable if ANY provider can serve it. The interplay with the
DMCA blocklist matters: an RD 451 no longer buries a source — TorBox gets
a shot first, and hashes already on the blocklist (including ones recorded
before TorBox existed) are still probed on TorBox, RD skipped. A hash is
only blocklisted when no configured provider can play it.

# `any_configured?`

# `attach_tracks`

Attach real audio/subtitle languages to probed streams, so the picker can
show them and ranking can trust them over release-name guesses.

Done as one concurrent batch rather than inside each probe: RD reads the
container server-side the first time it is asked about a stream, which
costs about 1.8s — paid per source while probing (two at a time) that is
most of a minute for a full page, and paid all at once here it is one
round trip. Best-effort throughout: a stream whose lookup fails simply has
no `:tracks` and its row falls back to what the release name says.

# `probe_sources`

Concurrently resolve a batch of `{source, index}` tuples across all
providers, reporting each outcome through `opts[:notify]` as
`{:result, index, source, {:ok, stream} | {:error, reason}}`.

# `resolve_best`

Try a ranked list of sources and return the first that plays on any
provider. Reports `{:trying, name}` / `{:skipped, name, reason}` through
`opts[:notify]`. Returns `{:ok, stream, source, skipped}` or
`{:error, {:all_failed, skipped}}`.

# `resolve_magnet`

Resolve on the first provider that can play the magnet. RD's error is
returned when everything fails (it's the primary; its reasons are the
most specific). `{:ok, stream}` — stream carries `:provider`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
