feat: upcoming movies on discover

pull/175/head
sct 4 years ago
parent 2b46268824
commit 67290dd502

@ -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

@ -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<TmdbUpcomingMoviesResponse> => {
try {
const response = await this.axios.get<TmdbUpcomingMoviesResponse>(
'/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',

@ -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();

@ -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<MediaResultsResponse>(
'/api/v1/media?filter=available&take=20&sort=modified'
);
@ -128,6 +133,49 @@ const Discover: React.FC = () => {
))}
emptyMessage={intl.formatMessage(messages.nopending)}
/>
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
<div className="flex-1 min-w-0">
<Link href="/discover/movies/upcoming">
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
<span>
<FormattedMessage {...messages.upcoming} />
</span>
<svg
className="w-6 h-6 ml-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</a>
</Link>
</div>
</div>
<Slider
sliderKey="movies"
isLoading={!movieUpcomingData && !movieUpcomingError}
isEmpty={false}
items={movieUpcomingData?.results.map((title) => (
<TitleCard
key={`upcoming-movie-slider-${title.id}`}
id={title.id}
image={title.posterPath}
status={title.mediaInfo?.status}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
year={title.releaseDate}
mediaType={title.mediaType}
/>
))}
/>
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
<div className="flex-1 min-w-0">
<Link href="/discover/movies">

@ -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",

@ -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": "",

Loading…
Cancel
Save