Skip to content

Commit 0bfe528

Browse files
authored
feat: batch fetch Plex items (#53)
1 parent de85101 commit 0bfe528

File tree

5 files changed

+50
-55
lines changed

5 files changed

+50
-55
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
- Plex episodes with year-based seasons are mapped to the correct TMDb season
2121
numbers via a helper that matches season names or air-date years to ensure
2222
accurate episode lookups.
23+
- Plex metadata is fetched in batches using `fetchItems` to reduce repeated
24+
network calls when loading library items.
2325

2426
## User Queries
2527
The project should handle natural-language searches and recommendations such as:

mcp_plex/loader.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,25 +316,24 @@ async def _augment_episode(
316316
results: List[AggregatedItem] = []
317317
async with httpx.AsyncClient(timeout=30) as client:
318318
movie_section = server.library.section("Movies")
319-
movie_tasks = [
320-
_augment_movie(client, movie.fetchItem(movie.ratingKey))
321-
for movie in movie_section.all()
322-
]
319+
movie_keys = [int(m.ratingKey) for m in movie_section.all()]
320+
movies = server.fetchItems(movie_keys) if movie_keys else []
321+
movie_tasks = [_augment_movie(client, movie) for movie in movies]
323322
if movie_tasks:
324323
results.extend(await _gather_in_batches(movie_tasks, batch_size))
325324

326325
show_section = server.library.section("TV Shows")
327-
for show in show_section.all():
328-
full_show = show.fetchItem(show.ratingKey)
326+
show_keys = [int(s.ratingKey) for s in show_section.all()]
327+
full_shows = server.fetchItems(show_keys) if show_keys else []
328+
for full_show in full_shows:
329329
show_ids = _extract_external_ids(full_show)
330330
show_tmdb: Optional[TMDBShow] = None
331331
if show_ids.tmdb:
332332
show_tmdb = await _fetch_tmdb_show(client, show_ids.tmdb, tmdb_api_key)
333+
episode_keys = [int(e.ratingKey) for e in full_show.episodes()]
334+
episodes = server.fetchItems(episode_keys) if episode_keys else []
333335
episode_tasks = [
334-
_augment_episode(
335-
client, episode.fetchItem(episode.ratingKey), show_tmdb
336-
)
337-
for episode in full_show.episodes()
336+
_augment_episode(client, episode, show_tmdb) for episode in episodes
338337
]
339338
if episode_tasks:
340339
results.extend(await _gather_in_batches(episode_tasks, batch_size))

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "mcp-plex"
7-
version = "0.26.18"
7+
version = "0.26.19"
88

99
description = "Plex-Oriented Model Context Protocol Server"
1010
requires-python = ">=3.11,<3.13"

tests/test_load_from_plex.py

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,55 @@
88

99

1010
def test_load_from_plex(monkeypatch):
11-
def add_fetch(obj):
12-
obj.fetchItem = lambda key: obj
13-
return obj
14-
15-
movie = add_fetch(
16-
types.SimpleNamespace(
17-
ratingKey="101",
18-
guid="plex://movie/101",
19-
type="movie",
20-
title="Inception",
21-
guids=[
22-
types.SimpleNamespace(id="imdb://tt1375666"),
23-
types.SimpleNamespace(id="tmdb://27205"),
24-
],
25-
)
11+
movie = types.SimpleNamespace(
12+
ratingKey="101",
13+
guid="plex://movie/101",
14+
type="movie",
15+
title="Inception",
16+
guids=[
17+
types.SimpleNamespace(id="imdb://tt1375666"),
18+
types.SimpleNamespace(id="tmdb://27205"),
19+
],
2620
)
2721

28-
ep1 = add_fetch(
29-
types.SimpleNamespace(
30-
ratingKey="102",
31-
guid="plex://episode/102",
32-
type="episode",
33-
title="Pilot",
34-
parentIndex=1,
35-
index=1,
36-
guids=[
37-
types.SimpleNamespace(id="imdb://tt0959621"),
38-
types.SimpleNamespace(id="tmdb://62085"),
39-
],
40-
)
22+
ep1 = types.SimpleNamespace(
23+
ratingKey="102",
24+
guid="plex://episode/102",
25+
type="episode",
26+
title="Pilot",
27+
parentIndex=1,
28+
index=1,
29+
guids=[
30+
types.SimpleNamespace(id="imdb://tt0959621"),
31+
types.SimpleNamespace(id="tmdb://62085"),
32+
],
4133
)
42-
ep2 = add_fetch(
43-
types.SimpleNamespace(
44-
ratingKey="103",
45-
guid="plex://episode/103",
46-
type="episode",
47-
title="Cat's in the Bag...",
48-
guids=[types.SimpleNamespace(id="imdb://tt0959622")],
49-
)
34+
ep2 = types.SimpleNamespace(
35+
ratingKey="103",
36+
guid="plex://episode/103",
37+
type="episode",
38+
title="Cat's in the Bag...",
39+
guids=[types.SimpleNamespace(id="imdb://tt0959622")],
5040
)
5141

52-
show = add_fetch(
53-
types.SimpleNamespace(
54-
ratingKey="201",
55-
guids=[types.SimpleNamespace(id="tmdb://1396")],
56-
episodes=lambda: [ep1, ep2],
57-
)
42+
show = types.SimpleNamespace(
43+
ratingKey="201",
44+
guids=[types.SimpleNamespace(id="tmdb://1396")],
45+
episodes=lambda: [ep1, ep2],
5846
)
5947

6048
movie_section = types.SimpleNamespace(all=lambda: [movie])
6149
show_section = types.SimpleNamespace(all=lambda: [show])
6250
library = types.SimpleNamespace(
6351
section=lambda name: movie_section if name == "Movies" else show_section
6452
)
65-
server = types.SimpleNamespace(library=library)
53+
54+
items = {101: movie, 102: ep1, 103: ep2, 201: show}
55+
56+
def fetchItems(keys):
57+
return [items[int(k)] for k in keys]
58+
59+
server = types.SimpleNamespace(library=library, fetchItems=fetchItems)
6660

6761
async def handler(request):
6862
url = str(request.url)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)