get_recently_watched
Retrieve a list of recently watched movies, shows, or episodes from Plex Media Server. Filter results by media type and set a limit for the number of items returned.
Instructions
Get recently watched movies and shows
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of items to return (default: 25) | |
| mediaType | No | Filter by media type (movie, show, episode, all) | all |
Implementation Reference
- src/index.ts:631-726 (handler)Core handler function implementing the get_recently_watched tool logic. Primarily uses getWatchHistory but falls back to scanning libraries for recently viewed items based on lastViewedAt.private async getRecentlyWatched(limit: number, mediaType: string) { // Use the working watch history function as the foundation try { const historyResult = await this.getWatchHistory(limit, undefined, mediaType); const historyData = JSON.parse(historyResult.content[0].text); // Transform watch history into recently watched format return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: historyData.watchHistory || [], totalCount: historyData.totalSessions || 0, note: "Retrieved from watch history data", }, null, 2), }, ], }; } catch (error) { // Fallback to library metadata approach try { const librariesData = await this.makeRequest("/library/sections"); const libraries = librariesData.MediaContainer?.Directory || []; let allRecentItems: any[] = []; for (const library of libraries) { try { const params: Record<string, any> = { sort: "lastViewedAt:desc", "X-Plex-Container-Size": Math.ceil(limit / libraries.length) + 5, }; if (mediaType !== "all") { params.type = this.getPlexTypeId(mediaType); } const contentData = await this.makeRequest(`/library/sections/${library.key}/all`, params); const content = contentData.MediaContainer?.Metadata || []; // Filter items that have been viewed recently const viewedContent = content.filter((item: any) => item.lastViewedAt && item.viewCount > 0 ); allRecentItems.push(...viewedContent); } catch (libError) { continue; } } // Sort by last viewed date and take requested number allRecentItems.sort((a: any, b: any) => (b.lastViewedAt || 0) - (a.lastViewedAt || 0)); allRecentItems = allRecentItems.slice(0, limit); return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: allRecentItems.map((item: any) => ({ ratingKey: item.ratingKey, title: item.title, type: item.type, year: item.year, lastViewedAt: item.lastViewedAt, viewCount: item.viewCount, duration: item.duration, viewOffset: item.viewOffset || 0, progress: item.viewOffset && item.duration ? Math.round((item.viewOffset / item.duration) * 100) : 100, })), totalCount: allRecentItems.length, note: "Retrieved from library metadata", }, null, 2), }, ], }; } catch (fallbackError) { return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: [], totalCount: 0, error: "Recently watched data not available", message: "Unable to retrieve recently watched content from this Plex server", }, null, 2), }, ], }; } } }
- src/index.ts:113-128 (schema)Input schema definition for the get_recently_watched tool, specifying parameters limit and mediaType.inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of items to return (default: 25)", default: 25, }, mediaType: { type: "string", description: "Filter by media type (movie, show, episode, all)", enum: ["movie", "show", "episode", "all"], default: "all", }, }, },
- src/index.ts:110-129 (registration)Tool registration in the ListTools response, defining name, description, and input schema for get_recently_watched.{ name: "get_recently_watched", description: "Get recently watched movies and shows", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of items to return (default: 25)", default: 25, }, mediaType: { type: "string", description: "Filter by media type (movie, show, episode, all)", enum: ["movie", "show", "episode", "all"], default: "all", }, }, }, },
- src/index.ts:278-282 (handler)Dispatcher case in the CallToolRequest handler that routes to the getRecentlyWatched method.case "get_recently_watched": return await this.getRecentlyWatched( ((args as any)?.limit as number) || 25, (args as any)?.mediaType as string || "all" );
- src/index.ts:634-726 (helper)Invocation of helper method getWatchHistory used as primary data source for recently watched items.const historyResult = await this.getWatchHistory(limit, undefined, mediaType); const historyData = JSON.parse(historyResult.content[0].text); // Transform watch history into recently watched format return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: historyData.watchHistory || [], totalCount: historyData.totalSessions || 0, note: "Retrieved from watch history data", }, null, 2), }, ], }; } catch (error) { // Fallback to library metadata approach try { const librariesData = await this.makeRequest("/library/sections"); const libraries = librariesData.MediaContainer?.Directory || []; let allRecentItems: any[] = []; for (const library of libraries) { try { const params: Record<string, any> = { sort: "lastViewedAt:desc", "X-Plex-Container-Size": Math.ceil(limit / libraries.length) + 5, }; if (mediaType !== "all") { params.type = this.getPlexTypeId(mediaType); } const contentData = await this.makeRequest(`/library/sections/${library.key}/all`, params); const content = contentData.MediaContainer?.Metadata || []; // Filter items that have been viewed recently const viewedContent = content.filter((item: any) => item.lastViewedAt && item.viewCount > 0 ); allRecentItems.push(...viewedContent); } catch (libError) { continue; } } // Sort by last viewed date and take requested number allRecentItems.sort((a: any, b: any) => (b.lastViewedAt || 0) - (a.lastViewedAt || 0)); allRecentItems = allRecentItems.slice(0, limit); return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: allRecentItems.map((item: any) => ({ ratingKey: item.ratingKey, title: item.title, type: item.type, year: item.year, lastViewedAt: item.lastViewedAt, viewCount: item.viewCount, duration: item.duration, viewOffset: item.viewOffset || 0, progress: item.viewOffset && item.duration ? Math.round((item.viewOffset / item.duration) * 100) : 100, })), totalCount: allRecentItems.length, note: "Retrieved from library metadata", }, null, 2), }, ], }; } catch (fallbackError) { return { content: [ { type: "text", text: JSON.stringify({ recentlyWatched: [], totalCount: 0, error: "Recently watched data not available", message: "Unable to retrieve recently watched content from this Plex server", }, null, 2), }, ], }; } } }