mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2025-12-31 19:59:31 -05:00
This commit is contained in:
93
src/components/Discover/DiscoverTvUpcoming.tsx
Normal file
93
src/components/Discover/DiscoverTvUpcoming.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useSWRInfinite } from 'swr';
|
||||
import type { TvResult } from '../../../server/models/Search';
|
||||
import ListView from '../Common/ListView';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import Header from '../Common/Header';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
|
||||
const messages = defineMessages({
|
||||
upcomingtv: 'Upcoming Series',
|
||||
});
|
||||
|
||||
interface SearchResult {
|
||||
page: number;
|
||||
totalResults: number;
|
||||
totalPages: number;
|
||||
results: TvResult[];
|
||||
}
|
||||
|
||||
const DiscoverTvUpcoming: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
|
||||
(pageIndex: number, previousPageData: SearchResult | null) => {
|
||||
if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `/api/v1/discover/tv/upcoming?page=${
|
||||
pageIndex + 1
|
||||
}&language=${locale}`;
|
||||
},
|
||||
{
|
||||
initialSize: 3,
|
||||
}
|
||||
);
|
||||
|
||||
const isLoadingInitialData = !data && !error;
|
||||
const isLoadingMore =
|
||||
isLoadingInitialData ||
|
||||
(size > 0 && data && typeof data[size - 1] === 'undefined');
|
||||
|
||||
const fetchMore = () => {
|
||||
setSize(size + 1);
|
||||
};
|
||||
|
||||
if (error) {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as TvResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={intl.formatMessage(messages.upcomingtv)} />
|
||||
<div className="mt-1 mb-5">
|
||||
<Header>
|
||||
<FormattedMessage {...messages.upcomingtv} />
|
||||
</Header>
|
||||
</div>
|
||||
<ListView
|
||||
items={titles}
|
||||
isEmpty={isEmpty}
|
||||
isReachingEnd={isReachingEnd}
|
||||
isLoading={
|
||||
isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)
|
||||
}
|
||||
onScrollBottom={fetchMore}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DiscoverTvUpcoming;
|
||||
@@ -15,6 +15,7 @@ const messages = defineMessages({
|
||||
recentrequests: 'Recent Requests',
|
||||
popularmovies: 'Popular Movies',
|
||||
populartv: 'Popular Series',
|
||||
upcomingtv: 'Upcoming Series',
|
||||
recentlyAdded: 'Recently Added',
|
||||
nopending: 'No Pending Requests',
|
||||
upcoming: 'Upcoming Movies',
|
||||
@@ -97,12 +98,6 @@ const Discover: React.FC = () => {
|
||||
placeholder={<RequestCard.Placeholder />}
|
||||
emptyMessage={intl.formatMessage(messages.nopending)}
|
||||
/>
|
||||
<MediaSlider
|
||||
sliderKey="upcoming"
|
||||
title={intl.formatMessage(messages.upcoming)}
|
||||
linkUrl="/discover/movies/upcoming"
|
||||
url="/api/v1/discover/movies/upcoming"
|
||||
/>
|
||||
<MediaSlider
|
||||
sliderKey="trending"
|
||||
title={intl.formatMessage(messages.trending)}
|
||||
@@ -115,12 +110,24 @@ const Discover: React.FC = () => {
|
||||
url="/api/v1/discover/movies"
|
||||
linkUrl="/discover/movies"
|
||||
/>
|
||||
<MediaSlider
|
||||
sliderKey="upcoming"
|
||||
title={intl.formatMessage(messages.upcoming)}
|
||||
linkUrl="/discover/movies/upcoming"
|
||||
url="/api/v1/discover/movies/upcoming"
|
||||
/>
|
||||
<MediaSlider
|
||||
sliderKey="popular-tv"
|
||||
title={intl.formatMessage(messages.populartv)}
|
||||
url="/api/v1/discover/tv"
|
||||
linkUrl="/discover/tv"
|
||||
/>
|
||||
<MediaSlider
|
||||
sliderKey="upcoming-tv"
|
||||
title={intl.formatMessage(messages.upcomingtv)}
|
||||
url="/api/v1/discover/tv/upcoming"
|
||||
linkUrl="/discover/tv/upcoming"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
185
src/components/RegionSelector/index.tsx
Normal file
185
src/components/RegionSelector/index.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Listbox, Transition } from '@headlessui/react';
|
||||
import { countryCodeEmoji } from 'country-code-emoji';
|
||||
import useSWR from 'swr';
|
||||
import type { Region } from '../../../server/lib/settings';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
regionDefault: 'All',
|
||||
});
|
||||
|
||||
interface RegionSelectorProps {
|
||||
value: string;
|
||||
name: string;
|
||||
onChange?: (fieldName: string, region: string) => void;
|
||||
}
|
||||
|
||||
const RegionSelector: React.FC<RegionSelectorProps> = ({
|
||||
name,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { data: regions } = useSWR<Region[]>('/api/v1/regions');
|
||||
const [selectedRegion, setSelectedRegion] = useState<Region | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (regions && value) {
|
||||
const matchedRegion = regions.find(
|
||||
(region) => region.iso_3166_1 === value
|
||||
);
|
||||
setSelectedRegion(matchedRegion ?? null);
|
||||
}
|
||||
}, [value, regions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onChange && regions) {
|
||||
onChange(name, selectedRegion?.iso_3166_1 ?? '');
|
||||
}
|
||||
}, [onChange, selectedRegion, name, regions]);
|
||||
|
||||
return (
|
||||
<div className="relative z-40 flex max-w-lg">
|
||||
<div className="w-full">
|
||||
<Listbox as="div" value={selectedRegion} onChange={setSelectedRegion}>
|
||||
{({ open }) => (
|
||||
<div className="relative">
|
||||
<span className="inline-block w-full rounded-md shadow-sm">
|
||||
<Listbox.Button className="relative flex items-center w-full py-2 pl-3 pr-10 text-left text-white transition duration-150 ease-in-out bg-gray-700 border border-gray-500 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5">
|
||||
{selectedRegion && (
|
||||
<span className="h-4 mr-2 overflow-hidden text-lg leading-4">
|
||||
{countryCodeEmoji(selectedRegion.iso_3166_1)}
|
||||
</span>
|
||||
)}
|
||||
<span className="block truncate">
|
||||
{selectedRegion
|
||||
? intl.formatDisplayName(selectedRegion.iso_3166_1, {
|
||||
type: 'region',
|
||||
})
|
||||
: intl.formatMessage(messages.regionDefault)}
|
||||
</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 20 20"
|
||||
className="w-5 h-5 text-gray-500"
|
||||
>
|
||||
<path
|
||||
stroke="#6b7280"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M6 8l4 4 4-4"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
</span>
|
||||
|
||||
<Transition
|
||||
show={open}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
className="absolute w-full mt-1 bg-gray-800 rounded-md shadow-lg"
|
||||
>
|
||||
<Listbox.Options
|
||||
static
|
||||
className="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5"
|
||||
>
|
||||
<Listbox.Option value={null}>
|
||||
{({ selected, active }) => (
|
||||
<div
|
||||
className={`${
|
||||
active ? 'text-white bg-indigo-600' : 'text-gray-300'
|
||||
} cursor-default select-none relative py-2 pl-8 pr-4`}
|
||||
>
|
||||
<span
|
||||
className={`${
|
||||
selected ? 'font-semibold' : 'font-normal'
|
||||
} block truncate`}
|
||||
>
|
||||
{intl.formatMessage(messages.regionDefault)}
|
||||
</span>
|
||||
{selected && (
|
||||
<span
|
||||
className={`${
|
||||
active ? 'text-white' : 'text-indigo-600'
|
||||
} absolute inset-y-0 left-0 flex items-center pl-1.5`}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
{regions?.map((region) => (
|
||||
<Listbox.Option key={region.iso_3166_1} value={region}>
|
||||
{({ selected, active }) => (
|
||||
<div
|
||||
className={`${
|
||||
active
|
||||
? 'text-white bg-indigo-600'
|
||||
: 'text-gray-300'
|
||||
} cursor-default select-none relative py-2 pl-8 pr-4 flex items-center`}
|
||||
>
|
||||
<span className="mr-2 text-lg">
|
||||
{countryCodeEmoji(region.iso_3166_1)}
|
||||
</span>
|
||||
<span
|
||||
className={`${
|
||||
selected ? 'font-semibold' : 'font-normal'
|
||||
} block truncate`}
|
||||
>
|
||||
{intl.formatDisplayName(region.iso_3166_1, {
|
||||
type: 'region',
|
||||
})}
|
||||
</span>
|
||||
{selected && (
|
||||
<span
|
||||
className={`${
|
||||
active ? 'text-white' : 'text-indigo-600'
|
||||
} absolute inset-y-0 left-0 flex items-center pl-1.5`}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Listbox>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RegionSelector;
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import useSWR from 'swr';
|
||||
import LoadingSpinner from '../Common/LoadingSpinner';
|
||||
import type { MainSettings } from '../../../server/lib/settings';
|
||||
import type { MainSettings, Language } from '../../../server/lib/settings';
|
||||
import CopyButton from './CopyButton';
|
||||
import { Form, Formik, Field } from 'formik';
|
||||
import axios from 'axios';
|
||||
@@ -13,6 +13,7 @@ import Badge from '../Common/Badge';
|
||||
import globalMessages from '../../i18n/globalMessages';
|
||||
import PermissionEdit from '../PermissionEdit';
|
||||
import * as Yup from 'yup';
|
||||
import RegionSelector from '../RegionSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
generalsettings: 'General Settings',
|
||||
@@ -23,6 +24,12 @@ const messages = defineMessages({
|
||||
apikey: 'API Key',
|
||||
applicationTitle: 'Application Title',
|
||||
applicationurl: 'Application URL',
|
||||
region: 'Discover Region',
|
||||
regionTip:
|
||||
'Filter content by region (only applies to the "Popular" and "Upcoming" categories)',
|
||||
originallanguage: 'Discover Language',
|
||||
originallanguageTip:
|
||||
'Filter content by original language (only applies to the "Popular" and "Upcoming" categories)',
|
||||
toastApiKeySuccess: 'New API key generated!',
|
||||
toastApiKeyFailure: 'Something went wrong while generating a new API key.',
|
||||
toastSettingsSuccess: 'Settings successfully saved!',
|
||||
@@ -50,6 +57,9 @@ const SettingsMain: React.FC = () => {
|
||||
const { data, error, revalidate } = useSWR<MainSettings>(
|
||||
'/api/v1/settings/main'
|
||||
);
|
||||
const { data: languages, error: languagesError } = useSWR<Language[]>(
|
||||
'/api/v1/languages'
|
||||
);
|
||||
const MainSettingsSchema = Yup.object().shape({
|
||||
applicationTitle: Yup.string().required(
|
||||
intl.formatMessage(messages.validationApplicationTitle)
|
||||
@@ -85,7 +95,7 @@ const SettingsMain: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
if (!data && !error) {
|
||||
if (!data && !error && !languages && !languagesError) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
@@ -108,6 +118,8 @@ const SettingsMain: React.FC = () => {
|
||||
defaultPermissions: data?.defaultPermissions ?? 0,
|
||||
hideAvailable: data?.hideAvailable,
|
||||
localLogin: data?.localLogin,
|
||||
region: data?.region,
|
||||
originalLanguage: data?.originalLanguage,
|
||||
trustProxy: data?.trustProxy,
|
||||
}}
|
||||
enableReinitialize
|
||||
@@ -121,6 +133,8 @@ const SettingsMain: React.FC = () => {
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
hideAvailable: values.hideAvailable,
|
||||
localLogin: values.localLogin,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
trustProxy: values.trustProxy,
|
||||
});
|
||||
|
||||
@@ -263,6 +277,51 @@ const SettingsMain: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="region" className="text-label">
|
||||
<span>{intl.formatMessage(messages.region)}</span>
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.regionTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input">
|
||||
<RegionSelector
|
||||
value={values.region ?? ''}
|
||||
name="region"
|
||||
onChange={setFieldValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="originalLanguage" className="text-label">
|
||||
<span>{intl.formatMessage(messages.originallanguage)}</span>
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.originallanguageTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input">
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field
|
||||
as="select"
|
||||
id="originalLanguage"
|
||||
name="originalLanguage"
|
||||
>
|
||||
<option value="">All</option>
|
||||
{languages?.map((language) => (
|
||||
<option
|
||||
key={`language-key-${language.iso_639_1}`}
|
||||
value={language.iso_639_1}
|
||||
>
|
||||
{intl.formatDisplayName(language.iso_639_1, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ?? language.english_name}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="hideAvailable" className="checkbox-label">
|
||||
<span className="mr-2">
|
||||
|
||||
@@ -5,11 +5,13 @@ import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import useSWR from 'swr';
|
||||
import { Language } from '../../../../../server/lib/settings';
|
||||
import { UserType, useUser } from '../../../../hooks/useUser';
|
||||
import Error from '../../../../pages/_error';
|
||||
import Badge from '../../../Common/Badge';
|
||||
import Button from '../../../Common/Button';
|
||||
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
||||
import RegionSelector from '../../../RegionSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
generalsettings: 'General Settings',
|
||||
@@ -20,6 +22,12 @@ const messages = defineMessages({
|
||||
localuser: 'Local User',
|
||||
toastSettingsSuccess: 'Settings successfully saved!',
|
||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||
region: 'Discover Region',
|
||||
regionTip:
|
||||
'Filter content by region (only applies to the "Popular" and "Upcoming" categories)',
|
||||
originallanguage: 'Discover Language',
|
||||
originallanguageTip:
|
||||
'Filter content by original language (only applies to the "Popular" and "Upcoming" categories)',
|
||||
});
|
||||
|
||||
const UserGeneralSettings: React.FC = () => {
|
||||
@@ -27,15 +35,25 @@ const UserGeneralSettings: React.FC = () => {
|
||||
const { addToast } = useToasts();
|
||||
const router = useRouter();
|
||||
const { user, mutate } = useUser({ id: Number(router.query.userId) });
|
||||
const { data, error, revalidate } = useSWR<{ username?: string }>(
|
||||
user ? `/api/v1/user/${user?.id}/settings/main` : null
|
||||
const { data, error, revalidate } = useSWR<{
|
||||
username?: string;
|
||||
region?: string;
|
||||
originalLanguage?: string;
|
||||
}>(user ? `/api/v1/user/${user?.id}/settings/main` : null);
|
||||
|
||||
const { data: languages, error: languagesError } = useSWR<Language[]>(
|
||||
'/api/v1/languages'
|
||||
);
|
||||
|
||||
if (!data && !error) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (!languages && !languagesError) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
if (!data || !languages) {
|
||||
return <Error statusCode={500} />;
|
||||
}
|
||||
|
||||
@@ -49,12 +67,16 @@ const UserGeneralSettings: React.FC = () => {
|
||||
<Formik
|
||||
initialValues={{
|
||||
displayName: data?.username,
|
||||
region: data?.region,
|
||||
originalLanguage: data?.originalLanguage,
|
||||
}}
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/main`, {
|
||||
username: values.displayName,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
});
|
||||
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
@@ -72,7 +94,7 @@ const UserGeneralSettings: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ errors, touched, isSubmitting }) => {
|
||||
{({ errors, touched, isSubmitting, values, setFieldValue }) => {
|
||||
return (
|
||||
<Form className="section">
|
||||
<div className="form-row">
|
||||
@@ -109,6 +131,51 @@ const UserGeneralSettings: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="displayName" className="text-label">
|
||||
<span>{intl.formatMessage(messages.region)}</span>
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.regionTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input">
|
||||
<RegionSelector
|
||||
name="region"
|
||||
value={values.region ?? ''}
|
||||
onChange={setFieldValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="originalLanguage" className="text-label">
|
||||
<span>{intl.formatMessage(messages.originallanguage)}</span>
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.originallanguageTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input">
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field
|
||||
as="select"
|
||||
id="originalLanguage"
|
||||
name="originalLanguage"
|
||||
>
|
||||
<option value="">All</option>
|
||||
{languages?.map((language) => (
|
||||
<option
|
||||
key={`language-key-${language.iso_639_1}`}
|
||||
value={language.iso_639_1}
|
||||
>
|
||||
{intl.formatDisplayName(language.iso_639_1, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ?? language.english_name}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<div className="flex justify-end">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"components.Discover.trending": "Trending",
|
||||
"components.Discover.upcoming": "Upcoming Movies",
|
||||
"components.Discover.upcomingmovies": "Upcoming Movies",
|
||||
"components.Discover.upcomingtv": "Upcoming Series",
|
||||
"components.Layout.LanguagePicker.changelanguage": "Change Language",
|
||||
"components.Layout.SearchInput.searchPlaceholder": "Search Movies & TV",
|
||||
"components.Layout.Sidebar.dashboard": "Discover",
|
||||
@@ -137,6 +138,7 @@
|
||||
"components.PlexLoginButton.loading": "Loading…",
|
||||
"components.PlexLoginButton.signingin": "Signing in…",
|
||||
"components.PlexLoginButton.signinwithplex": "Sign In",
|
||||
"components.RegionSelector.regionDefault": "All",
|
||||
"components.RequestBlock.profilechanged": "Quality Profile",
|
||||
"components.RequestBlock.requestoverrides": "Request Overrides",
|
||||
"components.RequestBlock.rootfolder": "Root Folder",
|
||||
@@ -514,6 +516,8 @@
|
||||
"components.Settings.notificationsettingsfailed": "Notification settings failed to save.",
|
||||
"components.Settings.notificationsettingssaved": "Notification settings saved!",
|
||||
"components.Settings.notrunning": "Not Running",
|
||||
"components.Settings.originallanguage": "Discover Language",
|
||||
"components.Settings.originallanguageTip": "Filter content by original language (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
||||
"components.Settings.plexlibraries": "Plex Libraries",
|
||||
"components.Settings.plexlibrariesDescription": "The libraries Overseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.",
|
||||
"components.Settings.plexsettings": "Plex Settings",
|
||||
@@ -521,6 +525,8 @@
|
||||
"components.Settings.port": "Port",
|
||||
"components.Settings.radarrSettingsDescription": "Configure your Radarr connection below. You can have multiple Radarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.",
|
||||
"components.Settings.radarrsettings": "Radarr Settings",
|
||||
"components.Settings.region": "Discover Region",
|
||||
"components.Settings.regionTip": "Filter content by region (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
||||
"components.Settings.save": "Save Changes",
|
||||
"components.Settings.saving": "Saving…",
|
||||
"components.Settings.serverConnected": "connected",
|
||||
@@ -671,7 +677,11 @@
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Display Name",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "General Settings",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Local User",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Discover Language",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filter content by original language (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Plex User",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Discover Region",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filter content by region (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Save Changes",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Saving…",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Something went wrong while saving settings.",
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import React from 'react';
|
||||
import { NextPage } from 'next';
|
||||
import DiscoverTv from '../../components/Discover/DiscoverTv';
|
||||
|
||||
const DiscoverMoviesPage: NextPage = () => {
|
||||
return <DiscoverTv />;
|
||||
};
|
||||
|
||||
export default DiscoverMoviesPage;
|
||||
9
src/pages/discover/tv/index.tsx
Normal file
9
src/pages/discover/tv/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import { NextPage } from 'next';
|
||||
import DiscoverTv from '../../../components/Discover/DiscoverTv';
|
||||
|
||||
const DiscoverTvPage: NextPage = () => {
|
||||
return <DiscoverTv />;
|
||||
};
|
||||
|
||||
export default DiscoverTvPage;
|
||||
9
src/pages/discover/tv/upcoming.tsx
Normal file
9
src/pages/discover/tv/upcoming.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import { NextPage } from 'next';
|
||||
import DiscoverTvUpcoming from '../../../components/Discover/DiscoverTvUpcoming';
|
||||
|
||||
const DiscoverTvPage: NextPage = () => {
|
||||
return <DiscoverTvUpcoming />;
|
||||
};
|
||||
|
||||
export default DiscoverTvPage;
|
||||
Reference in New Issue
Block a user