diff --git a/server/interfaces/api/settingsInterfaces.ts b/server/interfaces/api/settingsInterfaces.ts index 5136f17dc..122df7bd1 100644 --- a/server/interfaces/api/settingsInterfaces.ts +++ b/server/interfaces/api/settingsInterfaces.ts @@ -13,6 +13,7 @@ export interface PublicSettingsResponse { movie4kEnabled: boolean; series4kEnabled: boolean; region: string; + originalLanguage: string; } export interface CacheItem { diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 02320e00f..a65c5ffb0 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -85,6 +85,7 @@ interface FullPublicSettings extends PublicSettings { movie4kEnabled: boolean; series4kEnabled: boolean; region: string; + originalLanguage: string; } export interface NotificationAgentConfig { @@ -337,6 +338,7 @@ class Settings { (sonarr) => sonarr.is4k && sonarr.isDefault ), region: this.data.main.region, + originalLanguage: this.data.main.originalLanguage, }; } diff --git a/server/routes/discover.ts b/server/routes/discover.ts index 5b9d1afce..e248870ae 100644 --- a/server/routes/discover.ts +++ b/server/routes/discover.ts @@ -5,16 +5,35 @@ import Media from '../entity/Media'; import { isMovie, isPerson } from '../utils/typeHelpers'; import { MediaType } from '../constants/media'; import { getSettings } from '../lib/settings'; +import { User } from '../entity/User'; + +const createTmdbWithRegionLanaguage = (user?: User): TheMovieDb => { + const settings = getSettings(); + + const region = + user?.settings?.region === 'all' + ? '' + : user?.settings?.region + ? user?.settings?.region + : settings.main.region; + + const originalLanguage = + user?.settings?.originalLanguage === 'all' + ? '' + : user?.settings?.originalLanguage + ? user?.settings?.originalLanguage + : settings.main.originalLanguage; + + return new TheMovieDb({ + region, + originalLanguage, + }); +}; const discoverRoutes = Router(); discoverRoutes.get('/movies', async (req, res) => { - const settings = getSettings(); - const tmdb = new TheMovieDb({ - region: req.user?.settings?.region ?? settings.main.region, - originalLanguage: - req.user?.settings?.originalLanguage ?? settings.main.originalLanguage, - }); + const tmdb = createTmdbWithRegionLanaguage(req.user); const data = await tmdb.getDiscoverMovies({ page: Number(req.query.page), @@ -41,12 +60,7 @@ discoverRoutes.get('/movies', async (req, res) => { }); discoverRoutes.get('/movies/upcoming', async (req, res) => { - const settings = getSettings(); - const tmdb = new TheMovieDb({ - region: req.user?.settings?.region ?? settings.main.region, - originalLanguage: - req.user?.settings?.originalLanguage ?? settings.main.originalLanguage, - }); + const tmdb = createTmdbWithRegionLanaguage(req.user); const now = new Date(); const offset = now.getTimezoneOffset(); @@ -80,12 +94,7 @@ discoverRoutes.get('/movies/upcoming', async (req, res) => { }); discoverRoutes.get('/tv', async (req, res) => { - const settings = getSettings(); - const tmdb = new TheMovieDb({ - region: req.user?.settings?.region ?? settings.main.region, - originalLanguage: - req.user?.settings?.originalLanguage ?? settings.main.originalLanguage, - }); + const tmdb = createTmdbWithRegionLanaguage(req.user); const data = await tmdb.getDiscoverTv({ page: Number(req.query.page), @@ -112,12 +121,7 @@ discoverRoutes.get('/tv', async (req, res) => { }); discoverRoutes.get('/tv/upcoming', async (req, res) => { - const settings = getSettings(); - const tmdb = new TheMovieDb({ - region: req.user?.settings?.region ?? settings.main.region, - originalLanguage: - req.user?.settings?.originalLanguage ?? settings.main.originalLanguage, - }); + const tmdb = createTmdbWithRegionLanaguage(req.user); const now = new Date(); const offset = now.getTimezoneOffset(); @@ -151,12 +155,7 @@ discoverRoutes.get('/tv/upcoming', async (req, res) => { }); discoverRoutes.get('/trending', async (req, res) => { - const settings = getSettings(); - const tmdb = new TheMovieDb({ - region: req.user?.settings?.region ?? settings.main.region, - originalLanguage: - req.user?.settings?.originalLanguage ?? settings.main.originalLanguage, - }); + const tmdb = createTmdbWithRegionLanaguage(req.user); const data = await tmdb.getAllTrending({ page: Number(req.query.page), diff --git a/src/components/RegionSelector/index.tsx b/src/components/RegionSelector/index.tsx index 881174946..5d717c18b 100644 --- a/src/components/RegionSelector/index.tsx +++ b/src/components/RegionSelector/index.tsx @@ -1,37 +1,54 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, 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'; +import useSettings from '../../hooks/useSettings'; const messages = defineMessages({ regionDefault: 'All Regions', + regionServerDefault: '{applicationTitle} Default ({region})', }); interface RegionSelectorProps { value: string; name: string; + isUserSetting?: boolean; onChange?: (fieldName: string, region: string) => void; } const RegionSelector: React.FC = ({ name, value, + isUserSetting = false, onChange, }) => { + const { currentSettings } = useSettings(); const intl = useIntl(); const { data: regions } = useSWR('/api/v1/regions'); const [selectedRegion, setSelectedRegion] = useState(null); + const allRegion: Region = useMemo( + () => ({ + iso_3166_1: 'all', + english_name: 'All', + }), + [] + ); + useEffect(() => { if (regions && value) { - const matchedRegion = regions.find( - (region) => region.iso_3166_1 === value - ); - setSelectedRegion(matchedRegion ?? null); + if (value === 'all') { + setSelectedRegion(allRegion); + } else { + const matchedRegion = regions.find( + (region) => region.iso_3166_1 === value + ); + setSelectedRegion(matchedRegion ?? null); + } } - }, [value, regions]); + }, [value, regions, allRegion]); useEffect(() => { if (onChange && regions) { @@ -47,15 +64,26 @@ const RegionSelector: React.FC = ({
- {selectedRegion && ( + {selectedRegion && selectedRegion.iso_3166_1 !== 'all' && ( {countryCodeEmoji(selectedRegion.iso_3166_1)} )} - {selectedRegion + {selectedRegion && selectedRegion.iso_3166_1 !== 'all' ? intl.formatDisplayName(selectedRegion.iso_3166_1, { type: 'region', + fallback: 'none', + }) ?? selectedRegion.english_name + : isUserSetting && selectedRegion?.iso_3166_1 !== 'all' + ? intl.formatMessage(messages.regionServerDefault, { + applicationTitle: currentSettings.applicationTitle, + region: currentSettings.region + ? intl.formatDisplayName(currentSettings.region, { + type: 'region', + fallback: 'none', + }) ?? currentSettings.region + : intl.formatMessage(messages.regionDefault), }) : intl.formatMessage(messages.regionDefault)} @@ -89,7 +117,60 @@ const RegionSelector: React.FC = ({ 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" > - + {isUserSetting && ( + + {({ selected, active }) => ( +
+ + {intl.formatMessage(messages.regionServerDefault, { + applicationTitle: + currentSettings.applicationTitle, + region: currentSettings.region + ? intl.formatDisplayName( + currentSettings.region, + { + type: 'region', + fallback: 'none', + } + ) ?? currentSettings.region + : intl.formatMessage(messages.regionDefault), + })} + + {selected && ( + + + + + + )} +
+ )} +
+ )} + {({ selected, active }) => (
{ @@ -36,6 +38,7 @@ const UserGeneralSettings: React.FC = () => { const { addToast } = useToasts(); const router = useRouter(); const { user, mutate } = useUser({ id: Number(router.query.userId) }); + const { currentSettings } = useSettings(); const { data, error, revalidate } = useSWR<{ username?: string; region?: string; @@ -143,6 +146,7 @@ const UserGeneralSettings: React.FC = () => {
@@ -162,6 +166,19 @@ const UserGeneralSettings: React.FC = () => { name="originalLanguage" > + {languages?.map((language) => ( diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 02ce91d29..677b1aa66 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -139,6 +139,7 @@ "components.PlexLoginButton.signingin": "Signing in…", "components.PlexLoginButton.signinwithplex": "Sign In", "components.RegionSelector.regionDefault": "All Regions", + "components.RegionSelector.regionServerDefault": "{applicationTitle} Default ({region})", "components.RequestBlock.profilechanged": "Quality Profile", "components.RequestBlock.requestoverrides": "Request Overrides", "components.RequestBlock.rootfolder": "Root Folder", @@ -679,6 +680,7 @@ "components.UserProfile.ProfileHeader.settings": "Edit Settings", "components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Display Name", "components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "General Settings", + "components.UserProfile.UserSettings.UserGeneralSettings.languageServerDefault": "{applicationTitle} Default ({language})", "components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Local User", "components.UserProfile.UserSettings.UserGeneralSettings.originalLanguageDefault": "All Languages", "components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Discover Language",