feat(meta): TMDB search and movie lookup #49

Merged
naps62-yolo merged 4 commits from issue/14-tmdb into main 2026-08-22 19:52:58 +01:00
4 Commits
Author SHA1 Message Date
Miguel Palhas 738e871c70 Merge remote-tracking branch 'origin/main' into issue/14-tmdb
ci / web (pull_request) Successful in 25s
ci / rust (pull_request) Successful in 1m14s
# Conflicts:
#	Cargo.lock
2026-08-22 19:45:28 +01:00
Miguel Palhas 06d0675585 Merge remote-tracking branch 'origin/main' into issue/14-tmdb
ci / web (pull_request) Successful in 15s
ci / rust (pull_request) Successful in 53s
2026-08-22 19:43:12 +01:00
Miguel Palhas 502a431de3 fix(meta): derive the cache key from the encoded URL
Two ways a cached entry could be wrong.

The key was built by string concatenation in parallel with the URL, so
`search_movies("dune&year=2024", None)` and `search_movies("dune",
Some(2024))` produced the same key for two different requests. Both key
and URL now come from one `Url`, percent-encoded identically, and the
API key is appended at send time so it cannot reach a key or a log.

A successful response was cached before it was decoded, so one malformed
body returned `Error::Decode` from the cache for the whole time-to-live.
Decoding now happens first and only what decoded is stored.
2026-08-22 19:43:12 +01:00
Miguel Palhas 0fa422e170 feat(meta): TMDB search and movie lookup
ci / web (pull_request) Successful in 6s
ci / rust (pull_request) Successful in 46s
Search and detail lookup, carrying the two fields the policy engine
needs and that are easy to lose at the edge.

`original_language` arrives as bare ISO 639-1, which has one code for
both Portuguese variants, so the dub rule in §5.2 cannot be expressed
against it alone. `Movie` therefore also carries `origin_countries`,
from `origin_country` where TMDB has it and `production_countries`
otherwise, which is what separates a Brazilian film from a Portuguese
one.

Digital release dates come back appended to the detail call rather than
costing a second round trip, reduced to the earliest type-4 entry across
every country: a release existing in one region is a release that exists
on the indexers. `Movie::is_digitally_released` puts the §6.2 gate in
one tested place.

Responses are cached in process for a day, matching the metadata refresh
tick. Failures are never cached, so an outage cannot pin a title into a
bad state until tomorrow.

Tests are wiremock-backed, per §12.
2026-08-22 19:39:21 +01:00