From 8c27c00825b58247dd888c67d394159941aa740a Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Sat, 31 Aug 2024 18:06:58 +0530 Subject: [PATCH] TMDB changes, settings fixes (#1028) * Add fallback to TMDB description for series * Add TMDB search by ID for linking * Remove "Download All" options for TMDB titles and overviews * Remove TvDB settings * Refactor metadata site settings in first run * Refactor TMDB settings, add allow restricted in search option * Delete unused tvdb components --- .../Collection/CleanDescription.tsx | 17 +- src/components/Collection/ListViewItem.tsx | 15 +- src/components/Collection/SeriesTopPanel.tsx | 11 +- .../Collection/Tmdb/TmdbLinkSelectPanel.tsx | 13 +- .../MetadataSitesSettings/PlexSettings.tsx | 2 +- .../MetadataSitesSettings/TMDBSettings.tsx | 215 ++++++++++++++ .../MetadataSitesSettings/TraktSettings.tsx | 2 +- .../Settings/TvdbLanguageSelect.tsx | 51 ---- src/core/patches.ts | 5 + src/core/react-query/series/queries.ts | 3 +- src/core/react-query/settings/helpers.ts | 16 +- src/core/react-query/tmdb/queries.ts | 31 +- src/core/react-query/tmdb/types.ts | 5 + src/core/types/api/series.ts | 17 +- src/core/types/api/settings.ts | 44 +-- src/core/types/context.ts | 7 + src/hooks/UseFirstRunSettingsContext.tsx | 6 +- src/hooks/useSettingsContext.ts | 10 +- src/pages/collection/Collection.tsx | 2 +- src/pages/collection/Series.tsx | 2 +- .../collection/series/SeriesEpisodes.tsx | 2 +- .../collection/series/SeriesOverview.tsx | 2 +- .../dashboard/panels/RecommendedAnime.tsx | 4 +- src/pages/firstrun/MetadataSources.tsx | 91 +++--- .../firstrun/MetadataSourcesTabs/TMDBTab.tsx | 201 +------------ .../firstrun/MetadataSourcesTabs/TvDBTab.tsx | 133 --------- src/pages/settings/tabs/AniDBSettings.tsx | 8 +- src/pages/settings/tabs/ApiKeys.tsx | 4 +- .../settings/tabs/CollectionSettings.tsx | 6 +- src/pages/settings/tabs/GeneralSettings.tsx | 6 +- src/pages/settings/tabs/ImportSettings.tsx | 2 +- .../settings/tabs/MetadataSitesSettings.tsx | 281 +----------------- .../settings/tabs/UserManagementSettings.tsx | 8 +- 33 files changed, 405 insertions(+), 817 deletions(-) create mode 100644 src/components/Settings/MetadataSitesSettings/TMDBSettings.tsx delete mode 100644 src/components/Settings/TvdbLanguageSelect.tsx create mode 100644 src/core/types/context.ts delete mode 100644 src/pages/firstrun/MetadataSourcesTabs/TvDBTab.tsx diff --git a/src/components/Collection/CleanDescription.tsx b/src/components/Collection/CleanDescription.tsx index 012d4deef..bdcc787af 100644 --- a/src/components/Collection/CleanDescription.tsx +++ b/src/components/Collection/CleanDescription.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import cx from 'classnames'; // The question marks are there because people can't spell… const RemoveSummaryRegex = /\b(Sour?ce|Note|Summ?ary):([^\r\n]+|$)/mg; @@ -17,7 +18,13 @@ const CleanMultiEmptyLinesRegex = /\n{2,}/sg; const LinkRegex = /(?http:\/\/anidb\.net\/(?ch|cr|[feat]|(?:character|creator|file|episode|anime|tag)\/)(?\d+)) \[(?[^\]]+)]/g; -const CleanDescription = React.memo(({ className, text }: { text: string, className?: string }) => { +type Props = { + className?: string; + text: string; + altText?: string; +}; + +const CleanDescription = React.memo(({ altText, className, text }: Props) => { const modifiedText = useMemo(() => { const cleanedText = text .replaceAll(CleanMiscLinesRegex, '') @@ -47,7 +54,13 @@ const CleanDescription = React.memo(({ className, text }: { text: string, classN LinkRegex.lastIndex = 0; return lines.join(''); }, [text]); - return
{modifiedText}
; + + // Fallback to alt text if modified text is empty + if (modifiedText === '') { + return ; + } + + return
{modifiedText}
; }); export default CleanDescription; diff --git a/src/components/Collection/ListViewItem.tsx b/src/components/Collection/ListViewItem.tsx index 818b0ae12..c95cf0a9c 100644 --- a/src/components/Collection/ListViewItem.tsx +++ b/src/components/Collection/ListViewItem.tsx @@ -74,16 +74,18 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) => const missingEpisodesCount = item.Sizes.Total.Episodes + item.Sizes.Total.Specials - item.Sizes.Local.Episodes - item.Sizes.Local.Specials; - const [airDate, description, endDate, groupCount, isSeriesOngoing] = useMemo(() => { + const [airDate, description, altDescription, endDate, groupCount, isSeriesOngoing] = useMemo(() => { if (isSeries) { - const series = (item as SeriesType).AniDB; - const tempEndDate = dayjs(series?.EndDate); + const anidbSeries = (item as SeriesType).AniDB; + const tmdbSeries = (item as SeriesType).TMDB; + const tempEndDate = dayjs(anidbSeries?.EndDate); return [ - dayjs(series?.AirDate), + dayjs(anidbSeries?.AirDate), item.Description, + tmdbSeries?.Shows[0]?.Overview ?? tmdbSeries?.Movies[0]?.Overview ?? '', tempEndDate, 0, - series?.EndDate ? tempEndDate.isAfter(dayjs()) : true, + anidbSeries?.EndDate ? tempEndDate.isAfter(dayjs()) : true, ]; } @@ -93,6 +95,7 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) => return [ dayjs(groupExtras?.AirDate), group.Description, + undefined, tempEndDate, tempCount, groupExtras?.EndDate ? tempEndDate.isAfter(dayjs()) : true, @@ -275,7 +278,7 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) =>
- +
diff --git a/src/components/Collection/SeriesTopPanel.tsx b/src/components/Collection/SeriesTopPanel.tsx index 7f10a3a2c..d9db7f2f1 100644 --- a/src/components/Collection/SeriesTopPanel.tsx +++ b/src/components/Collection/SeriesTopPanel.tsx @@ -21,10 +21,6 @@ import useEventCallback from '@/hooks/useEventCallback'; import type { ImageType } from '@/core/types/api/common'; import type { SeriesType } from '@/core/types/api/series'; -type SeriesSidePanelProps = { - series: SeriesType; -}; - const SeriesTag = React.memo(({ text, type }: { text: string, type: 'User' | 'AniDB' }) => { const dispatch = useDispatch(); const navigate = useNavigate(); @@ -50,7 +46,7 @@ const SeriesTag = React.memo(({ text, type }: { text: string, type: 'User' | 'An ); }); -const SeriesTopPanel = React.memo(({ series }: SeriesSidePanelProps) => { +const SeriesTopPanel = React.memo(({ series }: { series: SeriesType }) => { const { WebUI_Settings: { collection: { image: { showRandomPoster } } } } = useSettingsQuery().data; const [poster, setPoster] = useState(null); const { seriesId } = useParams(); @@ -91,7 +87,10 @@ const SeriesTopPanel = React.memo(({ series }: SeriesSidePanelProps) => { contentClassName="contain-strict" transparent > - + { const [, setSearchParams] = useSearchParams(); const [linkType, setLinkType] = useState<'Show' | 'Movie'>('Show'); - const [selectedId, setSelectedId] = useState(0); const [searchText, setSearchText] = useState(''); const [debouncedSearch] = useDebounceValue(searchText, 200); + const { includeRestricted } = useSettingsQuery().data.WebUI_Settings.collection.tmdb; + const autoSearchQuery = useTmdbAutoSearchQuery(toNumber(seriesId), debouncedSearch === '' && !!seriesId); const autoSearchResults = useMemo(() => { if (!autoSearchQuery.data) return []; @@ -69,12 +71,15 @@ const TmdbLinkSelectPanel = () => { .map(result => result[linkType]); }, [autoSearchQuery.data, linkType]); - const searchQuery = useTmdbSearchQuery(linkType, debouncedSearch, { pageSize: 25 }); + const searchQuery = useTmdbSearchQuery(linkType, debouncedSearch, { + includeRestricted, + pageSize: 25, + }); const { isPending: refreshPending, mutate: refreshData } = useTmdbRefreshMutation(linkType); const noResults = useMemo(() => { if (debouncedSearch === '') return autoSearchResults.length === 0; - return searchQuery.data?.List.length === 0; + return searchQuery.data?.length === 0; }, [autoSearchResults, debouncedSearch, searchQuery.data]); const isPending = useMemo( @@ -163,7 +168,7 @@ const TmdbLinkSelectPanel = () => { /> ))} - {debouncedSearch && searchQuery.data?.List.map(result => ( + {debouncedSearch && searchQuery.data?.map(result => ( { return (
-
Plex Options
+
Plex Options
diff --git a/src/components/Settings/MetadataSitesSettings/TMDBSettings.tsx b/src/components/Settings/MetadataSitesSettings/TMDBSettings.tsx new file mode 100644 index 000000000..46d7039f6 --- /dev/null +++ b/src/components/Settings/MetadataSitesSettings/TMDBSettings.tsx @@ -0,0 +1,215 @@ +import React from 'react'; +import cx from 'classnames'; +import { produce } from 'immer'; + +import Checkbox from '@/components/Input/Checkbox'; +import InputSmall from '@/components/Input/InputSmall'; +import useEventCallback from '@/hooks/useEventCallback'; + +import type { SettingsContextType } from '@/core/types/context'; + +type Props = SettingsContextType; + +const TMDBSettings = React.memo((props: Props) => { + const { newSettings, setNewSettings, updateSetting } = props; + + const { + AutoDownloadAlternateOrdering, + AutoDownloadBackdrops, + AutoDownloadCollections, + AutoDownloadCrewAndCast, + AutoDownloadLogos, + AutoDownloadPosters, + AutoDownloadStaffImages, + AutoDownloadStudioImages, + AutoDownloadThumbnails, + AutoLink, + AutoLinkRestricted, + MaxAutoBackdrops, + MaxAutoLogos, + MaxAutoPosters, + MaxAutoStaffImages, + MaxAutoThumbnails, + } = newSettings.TMDB; + + const { includeRestricted } = newSettings.WebUI_Settings.collection.tmdb; + + const handleInputChange: React.ChangeEventHandler = useEventCallback((event) => { + const propId = event.target.id.replace('TMDB_', ''); + const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value; + updateSetting('TMDB', propId, value); + }); + + const handleIncludeRestrictedChange = useEventCallback((event: React.ChangeEvent) => { + const value = event.target.checked; + setNewSettings(produce(newSettings, (draftState) => { + draftState.WebUI_Settings.collection.tmdb.includeRestricted = value; + })); + }); + + return ( + <> + + + + + + + +
+ Max Backdrops + +
+ +
+ Max Posters + +
+ +
+ Max Logos + +
+ +
+ Max Episode Thumbnails + +
+ +
+ Max Staff Images + +
+ + + ); +}); + +export default TMDBSettings; diff --git a/src/components/Settings/MetadataSitesSettings/TraktSettings.tsx b/src/components/Settings/MetadataSitesSettings/TraktSettings.tsx index f9f4fbb2d..0c8878ba9 100644 --- a/src/components/Settings/MetadataSitesSettings/TraktSettings.tsx +++ b/src/components/Settings/MetadataSitesSettings/TraktSettings.tsx @@ -62,7 +62,7 @@ const TraktSettings = () => { return (
-
Trakt Options
+
Trakt Options
; -}; - -const TvdbLanguageSelect = ({ id, label, onChange, value }: Props) => ( - - {tvdbLanguages.map( - item => , - )} - -); - -export default TvdbLanguageSelect; diff --git a/src/core/patches.ts b/src/core/patches.ts index 07a509559..bd29545f9 100644 --- a/src/core/patches.ts +++ b/src/core/patches.ts @@ -35,5 +35,10 @@ export const webuiSettingsPatches = { delete webuiSettings.collection.image.showRandomFanart; return { ...webuiSettings, settingsRevision: 8 }; }, + 9: (oldWebuiSettings) => { + const webuiSettings = oldWebuiSettings; + webuiSettings.collection.tmdb.includeRestricted = false; + return { ...webuiSettings, settingsRevision: 9 }; + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record WebUISettingsType>; diff --git a/src/core/react-query/series/queries.ts b/src/core/react-query/series/queries.ts index ebb6f4584..5cf1b951a 100644 --- a/src/core/react-query/series/queries.ts +++ b/src/core/react-query/series/queries.ts @@ -23,7 +23,6 @@ import type { SeriesAniDBSearchResult, SeriesAniDBSimilarType, SeriesCast, - SeriesDetailsType, SeriesRecommendedType, SeriesType, } from '@/core/types/api/series'; @@ -34,7 +33,7 @@ export const useSeriesQuery = ( params: SeriesRequestType, enabled = true, ) => - useQuery({ + useQuery({ queryKey: ['series', seriesId, 'data', params], queryFn: () => axios.get(`Series/${seriesId}`, { params }), enabled, diff --git a/src/core/react-query/settings/helpers.ts b/src/core/react-query/settings/helpers.ts index 0b1699c7c..fcb20a934 100644 --- a/src/core/react-query/settings/helpers.ts +++ b/src/core/react-query/settings/helpers.ts @@ -284,6 +284,9 @@ export const initialSettings: SettingsType = { showRandomPoster: false, useThumbnailFallback: false, }, + tmdb: { + includeRestricted: false, + }, }, dashboard: { hideQueueProcessor: false, @@ -344,17 +347,6 @@ export const initialSettings: SettingsType = { Notification_UpdateFrequency: 1, Notification_HandleMovedFiles: false, }, - TvDB: { - AutoLink: false, - AutoFanart: false, - AutoFanartAmount: 0, - AutoWideBanners: false, - AutoWideBannersAmount: 0, - AutoPosters: false, - AutoPostersAmount: 0, - UpdateFrequency: 1, - Language: 'en', - }, TMDB: { AutoLink: false, AutoLinkRestricted: false, @@ -378,7 +370,7 @@ export const initialSettings: SettingsType = { }, Language: { UseSynonyms: false, - SeriesTitleLanguageOrder: [], + SeriesTitleLanguageOrder: ['x-main'], SeriesTitleSourceOrder: [LanguageSource.AniDB, LanguageSource.TMDB], EpisodeTitleLanguageOrder: ['en'], EpisodeTitleSourceOrder: [LanguageSource.TMDB, LanguageSource.TvDB, LanguageSource.AniDB], diff --git a/src/core/react-query/tmdb/queries.ts b/src/core/react-query/tmdb/queries.ts index b3faa5943..1158e84ef 100644 --- a/src/core/react-query/tmdb/queries.ts +++ b/src/core/react-query/tmdb/queries.ts @@ -1,10 +1,15 @@ import { useEffect } from 'react'; import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; +import { toNumber } from 'lodash'; import { axios } from '@/core/axios'; import queryClient from '@/core/react-query/queryClient'; -import type { TmdbBulkRequestType, TmdbEpisodeXRefRequestType } from '@/core/react-query/tmdb/types'; +import type { + TmdbBulkRequestType, + TmdbEpisodeXRefRequestType, + TmdbSearchRequestType, +} from '@/core/react-query/tmdb/types'; import type { ListResultType, PaginationType } from '@/core/types/api'; import type { TmdbAutoSearchResultType, @@ -75,11 +80,29 @@ export const useTmdbShowOrMovieQuery = (tmdbId: number, type: 'Show' | 'Movie', export const useTmdbSearchQuery = ( type: 'Show' | 'Movie', query: string, - params: PaginationType, + params: TmdbSearchRequestType, ) => - useQuery>({ + useQuery({ queryKey: ['series', 'tmdb', 'search', type, query, params], - queryFn: () => axios.get(`Tmdb/${type}/Online/Search`, { params: { ...params, query } }), + queryFn: async () => { + const finalData: TmdbSearchResultType[] = []; + + if (toNumber(query) !== 0) { + try { + const idLookupData: TmdbSearchResultType = await axios.get(`Tmdb/${type}/Online/${query}`); + finalData.push(idLookupData); + } catch (e) { + // Ignore, show/movie not found on TMDB with provided ID + } + } + + const searchData: ListResultType = await axios.get(`Tmdb/${type}/Online/Search`, { + params: { ...params, query }, + }); + finalData.push(...searchData.List); + + return finalData; + }, enabled: query.length > 0, }); diff --git a/src/core/react-query/tmdb/types.ts b/src/core/react-query/tmdb/types.ts index 71cfcee80..05445f5a9 100644 --- a/src/core/react-query/tmdb/types.ts +++ b/src/core/react-query/tmdb/types.ts @@ -32,3 +32,8 @@ export type TmdbDeleteLinkRequestType = { EpisodeID?: number; Purge?: boolean; }; + +export type TmdbSearchRequestType = { + includeRestricted?: boolean; + year?: number; +} & PaginationType; diff --git a/src/core/types/api/series.ts b/src/core/types/api/series.ts index c10568970..850fcd7ee 100644 --- a/src/core/types/api/series.ts +++ b/src/core/types/api/series.ts @@ -1,8 +1,5 @@ import type { ImageType, ImagesType, RatingType } from './common'; - -export type SeriesDetailsType = SeriesType & { - AniDB?: SeriesAniDBType; -}; +import type { TmdbMovieType, TmdbShowType } from '@/core/types/api/tmdb'; export type SeriesType = { IDs: SeriesIDsType; @@ -15,7 +12,11 @@ export type SeriesType = { Created: string; Updated: string; Description: string; - AniDB?: SeriesAniDBType; + AniDB?: AniDBSeriesType; + TMDB?: { + Movies: TmdbMovieType[]; + Shows: TmdbShowType[]; + }; }; export type SeriesWithMultipleReleasesType = { @@ -53,7 +54,7 @@ export type SeriesIDsType = { }; }; -export type SeriesAniDBType = { +export type AniDBSeriesType = { ID: number; Type: SeriesTypeEnum; Restricted: boolean; @@ -91,7 +92,7 @@ export const enum SeriesRelationTypeEnum { } export type SeriesAniDBRecommendedForYou = { - Anime: SeriesAniDBType; + Anime: AniDBSeriesType; SimilarTo: number; }; @@ -154,7 +155,7 @@ export type SeriesSizesReducedEpisodeCountsType = { }; export type SeriesRecommendedType = { - Anime: SeriesAniDBType; + Anime: AniDBSeriesType; SimilarTo: number; }; diff --git a/src/core/types/api/settings.ts b/src/core/types/api/settings.ts index 105befcbb..06e0084b4 100644 --- a/src/core/types/api/settings.ts +++ b/src/core/types/api/settings.ts @@ -59,46 +59,6 @@ export type SettingsAnidbUpdateType = { Notification_HandleMovedFiles: boolean; }; -export type SettingsTvdbDownloadType = { - AutoFanart: boolean; - AutoPosters: boolean; - AutoWideBanners: boolean; - AutoLink: boolean; -}; - -export type SettingsTvdbLanguageType = - | 'zh' - | 'en' - | 'sv' - | 'no' - | 'da' - | 'fi' - | 'nl' - | 'de' - | 'it' - | 'es' - | 'fr' - | 'pl' - | 'hu' - | 'el' - | 'tr' - | 'ru' - | 'he' - | 'ja' - | 'pt' - | 'cs' - | 'sl' - | 'hr' - | 'ko'; - -export type SettingsTvdbPrefsType = { - AutoFanartAmount: number; - AutoPostersAmount: number; - AutoWideBannersAmount: number; - Language: SettingsTvdbLanguageType; - UpdateFrequency: SettingsUpdateFrequencyType; -}; - export type SettingsTraktType = { Enabled: boolean; TokenExpirationDate: string; @@ -393,7 +353,6 @@ export type SettingsServerType = { & SettingsAnidbDownloadType & SettingsAnidbMylistType & SettingsAnidbUpdateType; - TvDB: SettingsTvdbDownloadType & SettingsTvdbPrefsType; TMDB: SettingsTMDBType; Language: SettingsLanguageType; TraktTv: SettingsTraktType; @@ -449,6 +408,9 @@ export type WebUISettingsType = { showRandomBackdrop: boolean; useThumbnailFallback: boolean; }; + tmdb: { + includeRestricted: boolean; + }; }; dashboard: { hideQueueProcessor: boolean; diff --git a/src/core/types/context.ts b/src/core/types/context.ts new file mode 100644 index 000000000..f9224486b --- /dev/null +++ b/src/core/types/context.ts @@ -0,0 +1,7 @@ +import type { PluginRenamerSettingsType, SettingsType } from '@/core/types/api/settings'; + +export type SettingsContextType = { + newSettings: SettingsType; + setNewSettings: (settings: SettingsType) => void; + updateSetting: (type: string, key: string, value: string | string[] | boolean | PluginRenamerSettingsType) => void; +}; diff --git a/src/hooks/UseFirstRunSettingsContext.tsx b/src/hooks/UseFirstRunSettingsContext.tsx index f7323a6e0..23a8819df 100644 --- a/src/hooks/UseFirstRunSettingsContext.tsx +++ b/src/hooks/UseFirstRunSettingsContext.tsx @@ -1,11 +1,9 @@ import { useOutletContext } from 'react-router-dom'; -import type { SettingsType } from '@/core/types/api/settings'; +import type { SettingsContextType } from '@/core/types/context'; -type ContextType = { +type ContextType = SettingsContextType & { fetching: boolean; - newSettings: SettingsType; - setNewSettings: (settings: SettingsType) => void; updateSetting: (type: string, key: string, value: string | string[] | boolean) => void; saveSettings: () => Promise; }; diff --git a/src/hooks/useSettingsContext.ts b/src/hooks/useSettingsContext.ts index 4534c16c4..36ff12a83 100644 --- a/src/hooks/useSettingsContext.ts +++ b/src/hooks/useSettingsContext.ts @@ -1,13 +1,7 @@ import { useOutletContext } from 'react-router-dom'; -import type { PluginRenamerSettingsType, SettingsType } from '@/core/types/api/settings'; +import type { SettingsContextType } from '@/core/types/context'; -type ContextType = { - newSettings: SettingsType; - setNewSettings: (settings: SettingsType) => void; - updateSetting: (type: string, key: string, value: string | string[] | boolean | PluginRenamerSettingsType) => void; -}; - -const useSettingsContext = () => useOutletContext(); +const useSettingsContext = () => useOutletContext(); export default useSettingsContext; diff --git a/src/pages/collection/Collection.tsx b/src/pages/collection/Collection.tsx index ee0ac8b53..43bb59127 100644 --- a/src/pages/collection/Collection.tsx +++ b/src/pages/collection/Collection.tsx @@ -147,7 +147,7 @@ function Collection() { true, ), randomImages: showRandomPoster, - includeDataFrom: ['AniDB'], + includeDataFrom: ['AniDB', 'TMDB'], recursive: true, includeMissing: true, }, diff --git a/src/pages/collection/Series.tsx b/src/pages/collection/Series.tsx index e91ea2c5a..b7d4a91ce 100644 --- a/src/pages/collection/Series.tsx +++ b/src/pages/collection/Series.tsx @@ -55,7 +55,7 @@ const Series = () => { const { seriesId } = useParams(); const { showRandomBackdrop } = useSettingsQuery().data.WebUI_Settings.collection.image; - const seriesQuery = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB'] }, !!seriesId); + const seriesQuery = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB', 'TMDB'] }, !!seriesId); const series = useMemo(() => seriesQuery?.data ?? {} as SeriesType, [seriesQuery.data]); const imagesQuery = useSeriesImagesQuery(toNumber(seriesId!), !!seriesId); const groupQuery = useGroupQuery(series?.IDs?.ParentGroup ?? 0, !!series?.IDs?.ParentGroup); diff --git a/src/pages/collection/series/SeriesEpisodes.tsx b/src/pages/collection/series/SeriesEpisodes.tsx index 9cc49f75b..e09dd643f 100644 --- a/src/pages/collection/series/SeriesEpisodes.tsx +++ b/src/pages/collection/series/SeriesEpisodes.tsx @@ -68,7 +68,7 @@ const SeriesEpisodes = () => { setSelectedEpisodes(new Set()); }, [episodeFilterType, episodeFilterAvailability, episodeFilterWatched, episodeFilterHidden, debouncedSearch]); - const seriesQueryData = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB'] }, !!seriesId).data; + const seriesQueryData = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB', 'TMDB'] }, !!seriesId).data; const seriesEpisodesQuery = useSeriesEpisodesInfiniteQuery( toNumber(seriesId!), { diff --git a/src/pages/collection/series/SeriesOverview.tsx b/src/pages/collection/series/SeriesOverview.tsx index 43b15be85..5325a8202 100644 --- a/src/pages/collection/series/SeriesOverview.tsx +++ b/src/pages/collection/series/SeriesOverview.tsx @@ -30,7 +30,7 @@ const MetadataLinks = ['AniDB', 'TMDB', 'TraktTv', 'TvDB'] as const; const SeriesOverview = () => { const { seriesId } = useParams(); - const seriesQuery = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB'] }, !!seriesId); + const seriesQuery = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB', 'TMDB'] }, !!seriesId); const series = useMemo(() => seriesQuery?.data ?? {} as SeriesType, [seriesQuery.data]); const nextUpEpisodeQuery = useSeriesNextUpQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB', 'TvDB'], diff --git a/src/pages/dashboard/panels/RecommendedAnime.tsx b/src/pages/dashboard/panels/RecommendedAnime.tsx index d8349d7f0..202ab28a6 100644 --- a/src/pages/dashboard/panels/RecommendedAnime.tsx +++ b/src/pages/dashboard/panels/RecommendedAnime.tsx @@ -10,7 +10,7 @@ import { useRecommendedAnimeQuery } from '@/core/react-query/series/queries'; import { useSettingsQuery } from '@/core/react-query/settings/queries'; import type { RootState } from '@/core/store'; -import type { SeriesAniDBType } from '@/core/types/api/series'; +import type { AniDBSeriesType } from '@/core/types/api/series'; const RecommendedAnime = () => { const layoutEditMode = useSelector((state: RootState) => state.mainpage.layoutEditMode); @@ -22,7 +22,7 @@ const RecommendedAnime = () => { pageSize: 20, }); - const renderItem = (series: SeriesAniDBType, matches: number) => ( + const renderItem = (series: AniDBSeriesType, matches: number) => (
void; + tabKey: string; + title: string; + }, +) => { + const handleClick = useEventCallback(() => { + setActiveTab(tabKey); + }); - const dispatch = useDispatch(); - - const [activeTab, setActiveTab] = useState('anidb'); - const [status, setStatus] = useState({ type: 'success', text: '' }); - - const renderTabButton = (title: string, key: string) => ( + return ( ); +}); - const renderTabContent = () => { - switch (activeTab) { - case 'anidb': - return ; - case 'tvdb': - return ; - case 'moviedb': - return ; - default: - return ; - } - }; +const TabContent = React.memo(({ setStatus, tab }: { setStatus: (status: TestStatusType) => void, tab: string }) => { + switch (tab) { + case 'anidb': + return ; + case 'moviedb': + return ; + default: + return ; + } +}); - const handleSave = async () => { - await saveSettings(); - dispatch(setFirstRunSaved('metadata-sources')); - }; +function MetadataSources() { + const { saveSettings } = useFirstRunSettingsContext(); + + const dispatch = useDispatch(); + + const [activeTab, setActiveTab] = useState('anidb'); + const [status, setStatus] = useState({ type: 'success', text: '' }); + + const handleSave = useEventCallback(() => { + saveSettings() + .then(() => dispatch(setFirstRunSaved('metadata-sources'))) + .catch(console.error); + }); return ( @@ -65,21 +77,26 @@ function MetadataSources() {
Recently Imported
- {renderTabButton('AniDB', 'anidb')} - | - {renderTabButton('TMDB', 'moviedb')} + | - {renderTabButton('TVDB', 'tvdb')} - {/* TODO: Add plex and trakt settings. Currently they only work after the setup is completed. */} +
- {renderTabContent()} +