diff --git a/AGENTS.md b/AGENTS.md index efb7bf5..4ee55c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,8 @@ - Plex episodes with year-based seasons are mapped to the correct TMDb season numbers via a helper that matches season names or air-date years to ensure accurate episode lookups. +- Plex metadata is fetched in batches using `fetchItems` to reduce repeated + network calls when loading library items. ## User Queries The project should handle natural-language searches and recommendations such as: diff --git a/mcp_plex/loader.py b/mcp_plex/loader.py index bfd37ff..a4fe593 100644 --- a/mcp_plex/loader.py +++ b/mcp_plex/loader.py @@ -316,25 +316,24 @@ async def _augment_episode( results: List[AggregatedItem] = [] async with httpx.AsyncClient(timeout=30) as client: movie_section = server.library.section("Movies") - movie_tasks = [ - _augment_movie(client, movie.fetchItem(movie.ratingKey)) - for movie in movie_section.all() - ] + movie_keys = [int(m.ratingKey) for m in movie_section.all()] + movies = server.fetchItems(movie_keys) if movie_keys else [] + movie_tasks = [_augment_movie(client, movie) for movie in movies] if movie_tasks: results.extend(await _gather_in_batches(movie_tasks, batch_size)) show_section = server.library.section("TV Shows") - for show in show_section.all(): - full_show = show.fetchItem(show.ratingKey) + show_keys = [int(s.ratingKey) for s in show_section.all()] + full_shows = server.fetchItems(show_keys) if show_keys else [] + for full_show in full_shows: show_ids = _extract_external_ids(full_show) show_tmdb: Optional[TMDBShow] = None if show_ids.tmdb: show_tmdb = await _fetch_tmdb_show(client, show_ids.tmdb, tmdb_api_key) + episode_keys = [int(e.ratingKey) for e in full_show.episodes()] + episodes = server.fetchItems(episode_keys) if episode_keys else [] episode_tasks = [ - _augment_episode( - client, episode.fetchItem(episode.ratingKey), show_tmdb - ) - for episode in full_show.episodes() + _augment_episode(client, episode, show_tmdb) for episode in episodes ] if episode_tasks: results.extend(await _gather_in_batches(episode_tasks, batch_size)) diff --git a/pyproject.toml b/pyproject.toml index 0f1af9a..03a86d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mcp-plex" -version = "0.26.18" +version = "0.26.19" description = "Plex-Oriented Model Context Protocol Server" requires-python = ">=3.11,<3.13" diff --git a/tests/test_load_from_plex.py b/tests/test_load_from_plex.py index 0df8f60..7945fb6 100644 --- a/tests/test_load_from_plex.py +++ b/tests/test_load_from_plex.py @@ -8,53 +8,41 @@ def test_load_from_plex(monkeypatch): - def add_fetch(obj): - obj.fetchItem = lambda key: obj - return obj - - movie = add_fetch( - types.SimpleNamespace( - ratingKey="101", - guid="plex://movie/101", - type="movie", - title="Inception", - guids=[ - types.SimpleNamespace(id="imdb://tt1375666"), - types.SimpleNamespace(id="tmdb://27205"), - ], - ) + movie = types.SimpleNamespace( + ratingKey="101", + guid="plex://movie/101", + type="movie", + title="Inception", + guids=[ + types.SimpleNamespace(id="imdb://tt1375666"), + types.SimpleNamespace(id="tmdb://27205"), + ], ) - ep1 = add_fetch( - types.SimpleNamespace( - ratingKey="102", - guid="plex://episode/102", - type="episode", - title="Pilot", - parentIndex=1, - index=1, - guids=[ - types.SimpleNamespace(id="imdb://tt0959621"), - types.SimpleNamespace(id="tmdb://62085"), - ], - ) + ep1 = types.SimpleNamespace( + ratingKey="102", + guid="plex://episode/102", + type="episode", + title="Pilot", + parentIndex=1, + index=1, + guids=[ + types.SimpleNamespace(id="imdb://tt0959621"), + types.SimpleNamespace(id="tmdb://62085"), + ], ) - ep2 = add_fetch( - types.SimpleNamespace( - ratingKey="103", - guid="plex://episode/103", - type="episode", - title="Cat's in the Bag...", - guids=[types.SimpleNamespace(id="imdb://tt0959622")], - ) + ep2 = types.SimpleNamespace( + ratingKey="103", + guid="plex://episode/103", + type="episode", + title="Cat's in the Bag...", + guids=[types.SimpleNamespace(id="imdb://tt0959622")], ) - show = add_fetch( - types.SimpleNamespace( - ratingKey="201", - guids=[types.SimpleNamespace(id="tmdb://1396")], - episodes=lambda: [ep1, ep2], - ) + show = types.SimpleNamespace( + ratingKey="201", + guids=[types.SimpleNamespace(id="tmdb://1396")], + episodes=lambda: [ep1, ep2], ) movie_section = types.SimpleNamespace(all=lambda: [movie]) @@ -62,7 +50,13 @@ def add_fetch(obj): library = types.SimpleNamespace( section=lambda name: movie_section if name == "Movies" else show_section ) - server = types.SimpleNamespace(library=library) + + items = {101: movie, 102: ep1, 103: ep2, 201: show} + + def fetchItems(keys): + return [items[int(k)] for k in keys] + + server = types.SimpleNamespace(library=library, fetchItems=fetchItems) async def handler(request): url = str(request.url) diff --git a/uv.lock b/uv.lock index da098b1..f684ca9 100644 --- a/uv.lock +++ b/uv.lock @@ -690,7 +690,7 @@ wheels = [ [[package]] name = "mcp-plex" -version = "0.26.18" +version = "0.26.19" source = { editable = "." } dependencies = [ { name = "fastapi" },