diff --git a/overseerr-api.yml b/overseerr-api.yml index 3fcafe564..752a4fe7e 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -1895,6 +1895,51 @@ paths: - $ref: '#/components/schemas/MovieResult' - $ref: '#/components/schemas/TvResult' - $ref: '#/components/schemas/PersonResult' + /discover/keyword/{keywordId}/movies: + get: + summary: Request list of movies from keyword + description: Returns list of movies based on provided keyword ID in JSON format + tags: + - search + parameters: + - in: path + name: keywordId + required: true + schema: + type: number + example: 207317 + - in: query + name: page + schema: + type: number + example: 1 + default: 1 + - in: query + name: language + schema: + type: string + example: en + responses: + '200': + description: List of movies + content: + application/json: + schema: + type: object + properties: + page: + type: number + example: 1 + totalPages: + type: number + example: 20 + totalResults: + type: number + example: 200 + results: + type: array + items: + $ref: '#/components/schemas/MovieResult' /request: get: summary: Get all requests diff --git a/server/api/themoviedb.ts b/server/api/themoviedb.ts index d6e5cc783..6f87823b6 100644 --- a/server/api/themoviedb.ts +++ b/server/api/themoviedb.ts @@ -542,6 +542,32 @@ class TheMovieDb { } } + public async getMoviesByKeyword({ + keywordId, + page = 1, + language = 'en-US', + }: { + keywordId: number; + page?: number; + language?: string; + }): Promise { + try { + const response = await this.axios.get( + `/keyword/${keywordId}/movies`, + { + params: { + page, + language, + }, + } + ); + + return response.data; + } catch (e) { + throw new Error(`[TMDB] Failed to fetch movies by keyword: ${e.message}`); + } + } + public async getTvRecommendations({ tvId, page = 1, diff --git a/server/routes/discover.ts b/server/routes/discover.ts index e6c9de45b..1193354ce 100644 --- a/server/routes/discover.ts +++ b/server/routes/discover.ts @@ -121,4 +121,36 @@ discoverRoutes.get('/trending', async (req, res) => { }); }); +discoverRoutes.get<{ keywordId: string }>( + '/keyword/:keywordId/movies', + async (req, res) => { + const tmdb = new TheMovieDb(); + + const data = await tmdb.getMoviesByKeyword({ + keywordId: Number(req.params.keywordId), + page: Number(req.query.page), + language: req.query.language as string, + }); + + const media = await Media.getRelatedMedia( + data.results.map((result) => result.id) + ); + + return res.status(200).json({ + page: data.page, + totalPages: data.total_pages, + totalResults: data.total_results, + results: data.results.map((result) => + mapMovieResult( + result, + media.find( + (req) => + req.tmdbId === result.id && req.mediaType === MediaType.MOVIE + ) + ) + ), + }); + } +); + export default discoverRoutes;