From 67290dd502571a22dcf8559ac07f42e855275bd0 Mon Sep 17 00:00:00 2001 From: sct Date: Thu, 12 Nov 2020 23:38:26 +0000 Subject: [PATCH] feat: upcoming movies on discover --- overseerr-api.yml | 39 +++++++++++++++++++++++++ server/api/themoviedb.ts | 33 +++++++++++++++++++++ server/routes/discover.ts | 25 ++++++++++++++++ src/components/Discover/index.tsx | 48 +++++++++++++++++++++++++++++++ src/i18n/locale/en.json | 8 ++++++ src/i18n/locale/ja.json | 8 ++++++ 6 files changed, 161 insertions(+) diff --git a/overseerr-api.yml b/overseerr-api.yml index 03d5675bc..2e2278fd7 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -1453,6 +1453,45 @@ paths: type: array items: $ref: '#/components/schemas/MovieResult' + /discover/movies/upcoming: + get: + summary: Upcoming Movies + description: Returns a list of movies in JSON format + tags: + - search + parameters: + - in: query + name: page + schema: + type: number + example: 1 + default: 1 + - in: query + name: language + schema: + type: string + example: en + responses: + '200': + description: Results + 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' /discover/tv: get: summary: Discover TV shows diff --git a/server/api/themoviedb.ts b/server/api/themoviedb.ts index 05d5aee84..e4bad31f0 100644 --- a/server/api/themoviedb.ts +++ b/server/api/themoviedb.ts @@ -1,4 +1,5 @@ import axios, { AxiosInstance } from 'axios'; +import { number } from 'yup'; interface SearchOptions { query: string; @@ -100,6 +101,14 @@ interface TmdbSearchTvResponse extends TmdbPaginatedResponse { results: TmdbTvResult[]; } +interface TmdbUpcomingMoviesResponse extends TmdbPaginatedResponse { + dates: { + maximum: string; + minimum: string; + }; + results: TmdbMovieResult[]; +} + interface TmdbExternalIdResponse { movie_results: TmdbMovieResult[]; tv_results: TmdbTvResult[]; @@ -520,6 +529,30 @@ class TheMovieDb { } }; + public getUpcomingMovies = async ({ + page = 1, + language = 'en-US', + }: { + page: number; + language: string; + }): Promise => { + try { + const response = await this.axios.get( + '/movie/upcoming', + { + params: { + page, + language, + }, + } + ); + + return response.data; + } catch (e) { + throw new Error(`[TMDB] Failed to fetch upcoming movies: ${e.message}`); + } + }; + public getAllTrending = async ({ page = 1, timeWindow = 'day', diff --git a/server/routes/discover.ts b/server/routes/discover.ts index 78b2020a4..edcef169c 100644 --- a/server/routes/discover.ts +++ b/server/routes/discover.ts @@ -30,6 +30,31 @@ discoverRoutes.get('/movies', async (req, res) => { }); }); +discoverRoutes.get('/movies/upcoming', async (req, res) => { + const tmdb = new TheMovieDb(); + + const data = await tmdb.getUpcomingMovies({ + 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) + ) + ), + }); +}); + discoverRoutes.get('/tv', async (req, res) => { const tmdb = new TheMovieDb(); diff --git a/src/components/Discover/index.tsx b/src/components/Discover/index.tsx index 26e8c27c9..b5a284735 100644 --- a/src/components/Discover/index.tsx +++ b/src/components/Discover/index.tsx @@ -17,6 +17,7 @@ const messages = defineMessages({ populartv: 'Popular Series', recentlyAdded: 'Recently Added', nopending: 'No Pending Requests', + upcoming: 'Upcoming Movies', }); interface MovieDiscoverResult { @@ -43,6 +44,10 @@ const Discover: React.FC = () => { `/api/v1/discover/tv?language=${locale}` ); + const { data: movieUpcomingData, error: movieUpcomingError } = useSWR< + MovieDiscoverResult + >(`/api/v1/discover/movies/upcoming?language=${locale}`); + const { data: media, error: mediaError } = useSWR( '/api/v1/media?filter=available&take=20&sort=modified' ); @@ -128,6 +133,49 @@ const Discover: React.FC = () => { ))} emptyMessage={intl.formatMessage(messages.nopending)} /> +
+ +
+ ( + + ))} + />
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 352a8b976..11a37542c 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -1,14 +1,18 @@ { "components.Discover.discovermovies": "Discover Movies", "components.Discover.discovertv": "Discover Series", + "components.Discover.nopending": "No Pending Requests", "components.Discover.popularmovies": "Popular Movies", "components.Discover.populartv": "Popular Series", + "components.Discover.recentlyAdded": "Recently Added", "components.Discover.recentrequests": "Recent Requests", + "components.Discover.upcoming": "Upcoming Movies", "components.Layout.LanguagePicker.changelanguage": "Change Language", "components.Layout.SearchInput.searchPlaceholder": "Search Movies & TV", "components.Layout.Sidebar.dashboard": "Dashboard", "components.Layout.Sidebar.requests": "Requests", "components.Layout.Sidebar.settings": "Settings", + "components.Layout.Sidebar.users": "Users", "components.MovieDetails.available": "Available", "components.MovieDetails.budget": "Budget", "components.MovieDetails.cancelrequest": "Cancel Request", @@ -52,6 +56,10 @@ "components.Settings.startscan": "Start Scan", "components.Settings.sync": "Sync Plex Libraries", "components.Settings.syncing": "Syncing", + "components.Setup.continue": "Continue", + "components.Setup.finish": "Finish Setup", + "components.Setup.finishing": "Finishing...", + "components.Slider.noresults": "No Results", "components.TvDetails.approverequests": "Approve {requestCount} {requestCount, plural, one {Request} other {Requests}}", "components.TvDetails.available": "Available", "components.TvDetails.cancelrequest": "Cancel Request", diff --git a/src/i18n/locale/ja.json b/src/i18n/locale/ja.json index 7fefa71d4..68dbc8e08 100644 --- a/src/i18n/locale/ja.json +++ b/src/i18n/locale/ja.json @@ -1,14 +1,18 @@ { "components.Discover.discovermovies": "人気の映画", "components.Discover.discovertv": "人気のテレビ番組", + "components.Discover.nopending": "", "components.Discover.popularmovies": "人気の映画", "components.Discover.populartv": "人気のテレビ番組", + "components.Discover.recentlyAdded": "", "components.Discover.recentrequests": "最近のリクエスト", + "components.Discover.upcoming": "", "components.Layout.LanguagePicker.changelanguage": "言語", "components.Layout.SearchInput.searchPlaceholder": "作品名で検索", "components.Layout.Sidebar.dashboard": "ホーム", "components.Layout.Sidebar.requests": "リクエスト", "components.Layout.Sidebar.settings": "設定", + "components.Layout.Sidebar.users": "", "components.MovieDetails.available": "", "components.MovieDetails.budget": "興行収入", "components.MovieDetails.cancelrequest": "チャンセルリクエスト", @@ -52,6 +56,10 @@ "components.Settings.startscan": "", "components.Settings.sync": "", "components.Settings.syncing": "", + "components.Setup.continue": "", + "components.Setup.finish": "", + "components.Setup.finishing": "", + "components.Slider.noresults": "", "components.TvDetails.approverequests": "", "components.TvDetails.available": "", "components.TvDetails.cancelrequest": "",