Files
meta-feeder-tmdb/README.md
T
Worph c7299d549c
Publish image / publish (push) Failing after 13s
initial commit
2026-07-25 21:28:35 +02:00

4.0 KiB

meta-feeder-card

The card tier feeder for the MetaMesh gateway — the discovery half of gateway search.

A card is a metadata-only record identifying a work (a series, a film), not a file: title, poster, description, and an id bag of every cross-source identifier the bridge could resolve. It has no bytes, and by design never will.

Phase 1 — CARD (this feeder)          Phase 2 — RETRIEVAL (content feeders)
  <free text> fileType:card              fileType:video + the card's id bag
  one cached TMDB search/multi           the full indexer budget, ONE work
  → a poster grid of works               → the episode / version list
                        ── user clicks a card ──

Splitting the two halves is the point. Previously one query resolved ten speculative candidate works and searched every indexer for all of them, against a shared 1 req/s bucket — so the work the user actually wanted got a tenth of the budget. A card query touches TMDB only; the indexer budget is spent later, entirely on the card that was clicked.

Upstreams

upstream_id source status
tmdb themoviedb.org shipping
myanimelist myanimelist.net planned — a sibling FeederPlugin in this same binary

Both declare served_file_types = ["card"], which is the whole routing story: meta-search fans a fileType:card query out to every gateway advertising it, so adding this tier needed no meta-search change.

Card identity

A card's CID is a 0x1007 card locator — an identity-multihash CIDv1 whose payload is varint(len(source)) ‖ source ‖ id, e.g. ("tmdb", "tv:95479").

  • Deterministic in (source, id), so any peer holding a tmdb id derives the address offline, with no discovery round-trip — and the same card found by two peers converges on one meta-core record for free.
  • Ranks 5 (opaque-locator tier), so it never outranks a real digest. That is what will make a future cross-source merge — one meta-core record carrying both a TMDB and a MyAnimeList locator — safe.
  • Never seeded to bitswap (seeding is gated on sha2-256). Nothing to seed.

Cards are treated as immutable: no TTL, no refresh, and no drifting values (rating, popularity) stored on them. Growth is append-only — a future season card is an addition beside the series card, never an edit to it.

Config

Per-plugin config lives on the feeder (gateway invariant 12), served as a schema-driven form at GET /config:

key meaning
tmdb_token TMDB v4 read token. Required — without it the feeder soft-skips (stays healthy, returns no cards).
tmdb_rate_per_sec Sustained TMDB request rate. Default 20/s.
tmdb_burst Short-burst token ceiling. Default 20.
card_top_n Works returned per free-text search. Default 10. Costs no indexer requests.

Env (TMDB_TOKEN, TMDB_RATE_PER_SEC, TMDB_BURST, CARD_TOP_N) seeds the first boot; the config file wins from then on. No hot reload — bounce the feeder.

Build / run

cargo build --release --bin card-feeder
cargo test -p card-feeder

# Image (build context is the repo root so the vendored SDK path dep resolves)
docker build -f feeder-plugin/card-feeder/Dockerfile -t ghcr.io/worph/meta-feeder-card:dev .

Register it with a gateway by adding it to that gateway's gateway-config.json feeders map (or via the dashboard) and restarting:

{ "feeders": { "card-feeder": { "url": "http://card-feeder-hub:8080" } } }

Layout

crates/meta-feeder-sdk/        vendored SDK copy (mirrored from meta-gateway)
feeder-plugin/card-feeder/
  src/tmdb.rs                  the FeederPlugin impl — routing + query + outcomes
  src/card.rs                  the Card model + its DiscoveryRecord projection
  src/resolve.rs               cache- and budget-gated TMDB resolution
  src/tmdb_client.rs           TMDB v3 HTTP client + DTOs
  src/tmdb_budget.rs           token bucket
  src/consts.rs

Design rationale, including what was deliberately not built: meta-gateway/docs/others/card-tier-search.md.