feat(tmdb): add TmdbMovieInfo DTO and get_movie_info

Symmetric to TmdbShowInfo / get_tv_show_info — gives the upcoming
sync_movie orchestrator a typed cache snapshot for the v2 movie
library index.

* TmdbMovieInfo(tmdb_id, imdb_id, title, release_year)
* parse_movie_info(details, external_ids) — pure builder, parses
  release_year from the first 4 chars of release_date (None on
  missing/empty/non-numeric)
* TMDBClient.get_movie_info(tmdb_id) — aggregates
  /movie/{id} + /movie/{id}/external_ids and feeds the parser

Tests cover happy path, missing/null/empty imdb_id, every
release_year edge (none/empty/short/non-numeric/missing key),
and the two required-field errors (id, title).
This commit is contained in:
2026-05-26 00:35:42 +02:00
parent 97dc799a26
commit 0dc053881a
4 changed files with 242 additions and 1 deletions
@@ -360,6 +360,46 @@ class TestGetTvShowInfo:
assert info.seasons == ()
class TestGetMovieInfo:
"""``get_movie_info`` aggregates ``/movie/{id}`` + external_ids."""
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_happy_path(self, mock_get, client):
details = {
"id": 27205,
"title": "Inception",
"release_date": "2010-07-16",
}
external = {"imdb_id": "tt1375666"}
mock_get.side_effect = [
_ok_response(details),
_ok_response(external),
]
info = client.get_movie_info(27205)
assert info.tmdb_id == 27205
assert info.imdb_id == "tt1375666"
assert info.title == "Inception"
assert info.release_year == 2010
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_missing_imdb_id_becomes_none(self, mock_get, client):
mock_get.side_effect = [
_ok_response(
{
"id": 1,
"title": "X",
"release_date": "2024-01-01",
}
),
_ok_response({}),
]
info = client.get_movie_info(1)
assert info.imdb_id is None
assert info.release_year == 2024
class TestIsConfigured:
def test_true_when_complete(self, client):
assert client.is_configured() is True