From c778956a52fbdb04fa27c739f93dc9ed0127d299 Mon Sep 17 00:00:00 2001 From: stenlan <14372001+stenlan@users.noreply.github.com> Date: Wed, 3 Sep 2025 21:41:35 +0200 Subject: [PATCH] fix: Jellyseerr discovery crash (#1032) --- .../(home)/settings/hide-libraries/page.tsx | 2 +- .../(home)/settings/jellyseerr/page.tsx | 2 +- .../(home)/settings/marlin-search/page.tsx | 2 +- .../jellyseerr/company/[companyId].tsx | 11 +++--- .../jellyseerr/genre/[genreId].tsx | 17 ++++----- .../jellyseerr/person/[personId].tsx | 8 +--- app/(auth)/(tabs)/(libraries)/_layout.tsx | 2 +- app/(auth)/(tabs)/(libraries)/index.tsx | 2 +- app/(auth)/(tabs)/(search)/index.tsx | 2 +- app/(auth)/(tabs)/_layout.tsx | 2 +- app/(auth)/player/direct-player.tsx | 3 +- app/_layout.tsx | 2 +- components/DownloadItem.tsx | 2 +- components/ItemContent.tsx | 2 +- components/PlayButton.tsx | 2 +- components/PlayButton.tv.tsx | 2 +- components/common/JellyseerrItemRouter.tsx | 3 +- components/home/LargeMovieCarousel.tsx | 2 +- .../jellyseerr/discover/MovieTvSlide.tsx | 17 +++------ components/library/LibraryItemCard.tsx | 2 +- components/posters/JellyseerrPoster.tsx | 3 +- components/settings/AppLanguageSelector.tsx | 2 +- components/settings/AudioToggles.tsx | 2 +- components/settings/ChromecastSettings.tsx | 2 +- components/settings/Dashboard.tsx | 2 +- components/settings/DownloadSettings.tsx | 2 +- components/settings/GestureControls.tsx | 2 +- components/settings/HomeIndex.tsx | 8 +--- components/settings/Jellyseerr.tsx | 2 +- components/settings/MediaContext.tsx | 2 +- components/settings/MediaToggles.tsx | 2 +- components/settings/OtherSettings.tsx | 2 +- components/settings/PluginSettings.tsx | 2 +- components/settings/SubtitleToggles.tsx | 2 +- .../video-player/controls/BottomControls.tsx | 2 +- .../video-player/controls/CenterControls.tsx | 2 +- .../controls/ContinueWatchingOverlay.tsx | 2 +- components/video-player/controls/Controls.tsx | 2 +- .../video-player/controls/GestureOverlay.tsx | 2 +- .../video-player/controls/HeaderControls.tsx | 2 +- .../controls/hooks/useVideoNavigation.ts | 2 +- hooks/useHaptic.ts | 2 +- hooks/useJellyseerr.ts | 37 +++++++++---------- providers/DownloadProvider.tsx | 2 +- providers/JellyfinProvider.tsx | 13 +------ utils/_jellyseerr/useJellyseerrCanRequest.ts | 3 +- utils/atoms/queue.ts | 2 +- utils/atoms/settings.ts | 15 ++++---- 48 files changed, 90 insertions(+), 120 deletions(-) diff --git a/app/(auth)/(tabs)/(home)/settings/hide-libraries/page.tsx b/app/(auth)/(tabs)/(home)/settings/hide-libraries/page.tsx index da4dfef5..e1c8b56b 100644 --- a/app/(auth)/(tabs)/(home)/settings/hide-libraries/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/hide-libraries/page.tsx @@ -12,7 +12,7 @@ import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { useSettings } from "@/utils/atoms/settings"; export default function page() { - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const user = useAtomValue(userAtom); const api = useAtomValue(apiAtom); diff --git a/app/(auth)/(tabs)/(home)/settings/jellyseerr/page.tsx b/app/(auth)/(tabs)/(home)/settings/jellyseerr/page.tsx index 3e4e410e..86222f93 100644 --- a/app/(auth)/(tabs)/(home)/settings/jellyseerr/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/jellyseerr/page.tsx @@ -3,7 +3,7 @@ import { JellyseerrSettings } from "@/components/settings/Jellyseerr"; import { useSettings } from "@/utils/atoms/settings"; export default function page() { - const [_settings, _updateSettings, pluginSettings] = useSettings(null); + const { pluginSettings } = useSettings(); return ( (settings?.marlinServerUrl || ""); diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx index 4e7ba94b..cd9cc3cc 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx @@ -15,7 +15,7 @@ import { COMPANY_LOGO_IMAGE_FILTER } from "@/utils/jellyseerr/src/components/Dis export default function page() { const local = useLocalSearchParams(); - const { jellyseerrApi } = useJellyseerr(); + const { jellyseerrApi, isJellyseerrMovieOrTvResult } = useJellyseerr(); const { companyId, image, type } = local as unknown as { companyId: string; @@ -53,7 +53,10 @@ export default function page() { uniqBy( data?.pages ?.filter((p) => p?.results.length) - .flatMap((p) => p?.results ?? []), + .flatMap( + (p) => + p?.results.filter((r) => isJellyseerrMovieOrTvResult(r)) ?? [], + ), "id", ) ?? [], [data], @@ -98,9 +101,7 @@ export default function page() { }} /> } - renderItem={(item, _index) => ( - - )} + renderItem={(item, _index) => } /> ); } diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx index 5482c45d..7ea00808 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx @@ -8,14 +8,10 @@ import ParallaxSlideShow from "@/components/jellyseerr/ParallaxSlideShow"; import JellyseerrPoster from "@/components/posters/JellyseerrPoster"; import { Endpoints, useJellyseerr } from "@/hooks/useJellyseerr"; import { DiscoverSliderType } from "@/utils/jellyseerr/server/constants/discover"; -import { - type MovieResult, - type TvResult, -} from "@/utils/jellyseerr/server/models/Search"; export default function page() { const local = useLocalSearchParams(); - const { jellyseerrApi } = useJellyseerr(); + const { jellyseerrApi, isJellyseerrMovieOrTvResult } = useJellyseerr(); const { genreId, name, type } = local as unknown as { genreId: string; @@ -51,7 +47,10 @@ export default function page() { uniqBy( data?.pages ?.filter((p) => p?.results.length) - .flatMap((p) => p?.results ?? []), + .flatMap( + (p) => + p?.results.filter((r) => isJellyseerrMovieOrTvResult(r)) ?? [], + ), "id", ) ?? [], [data], @@ -62,7 +61,7 @@ export default function page() { jellyseerrApi ? flatData.map((r) => jellyseerrApi.imageProxy( - (r as TvResult | MovieResult).backdropPath, + r.backdropPath, "w1920_and_h800_multi_faces", ), ) @@ -92,9 +91,7 @@ export default function page() { {name} } - renderItem={(item, _index) => ( - - )} + renderItem={(item, _index) => } /> ); } diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/person/[personId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/person/[personId].tsx index 9c03aff4..7bef1d7a 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/person/[personId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/person/[personId].tsx @@ -10,10 +10,6 @@ import { OverviewText } from "@/components/OverviewText"; import JellyseerrPoster from "@/components/posters/JellyseerrPoster"; import { useJellyseerr } from "@/hooks/useJellyseerr"; import type { PersonCreditCast } from "@/utils/jellyseerr/server/models/Person"; -import type { - MovieResult, - TvResult, -} from "@/utils/jellyseerr/server/models/Search"; export default function page() { const local = useLocalSearchParams(); @@ -106,9 +102,7 @@ export default function page() { MainContent={() => ( )} - renderItem={(item, _index) => ( - - )} + renderItem={(item, _index) => } /> ); } diff --git a/app/(auth)/(tabs)/(libraries)/_layout.tsx b/app/(auth)/(tabs)/(libraries)/_layout.tsx index 6d032a7a..e450e3ec 100644 --- a/app/(auth)/(tabs)/(libraries)/_layout.tsx +++ b/app/(auth)/(tabs)/(libraries)/_layout.tsx @@ -9,7 +9,7 @@ const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null; import { useTranslation } from "react-i18next"; export default function IndexLayout() { - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const { t } = useTranslation(); diff --git a/app/(auth)/(tabs)/(libraries)/index.tsx b/app/(auth)/(tabs)/(libraries)/index.tsx index 75b4ef29..c638e5d2 100644 --- a/app/(auth)/(tabs)/(libraries)/index.tsx +++ b/app/(auth)/(tabs)/(libraries)/index.tsx @@ -19,7 +19,7 @@ export default function index() { const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); const queryClient = useQueryClient(); - const [settings] = useSettings(null); + const { settings } = useSettings(); const { t } = useTranslation(); diff --git a/app/(auth)/(tabs)/(search)/index.tsx b/app/(auth)/(tabs)/(search)/index.tsx index 8bab9bf1..5a95ad48 100644 --- a/app/(auth)/(tabs)/(search)/index.tsx +++ b/app/(auth)/(tabs)/(search)/index.tsx @@ -71,7 +71,7 @@ export default function search() { const [api] = useAtom(apiAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); const { jellyseerrApi } = useJellyseerr(); const [jellyseerrOrderBy, setJellyseerrOrderBy] = useState( diff --git a/app/(auth)/(tabs)/_layout.tsx b/app/(auth)/(tabs)/_layout.tsx index 622542b4..41a76eb6 100644 --- a/app/(auth)/(tabs)/_layout.tsx +++ b/app/(auth)/(tabs)/_layout.tsx @@ -27,7 +27,7 @@ export const NativeTabs = withLayoutContext< >(Navigator); export default function TabLayout() { - const [settings] = useSettings(null); + const { settings } = useSettings(); const { t } = useTranslation(); const router = useRouter(); diff --git a/app/(auth)/player/direct-player.tsx b/app/(auth)/player/direct-player.tsx index a8de9cca..ca906a78 100644 --- a/app/(auth)/player/direct-player.tsx +++ b/app/(auth)/player/direct-player.tsx @@ -97,7 +97,7 @@ export default function page() { /** Playback position in ticks. */ playbackPosition?: string; }>(); - const [_settings] = useSettings(null); + useSettings(); const offline = offlineStr === "true"; const playbackManager = usePlaybackManager(); @@ -748,7 +748,6 @@ export default function page() { setAspectRatio={setAspectRatio} setScaleFactor={setScaleFactor} isVlc - api={api} downloadedFiles={downloadedFiles} /> )} diff --git a/app/_layout.tsx b/app/_layout.tsx index 5b77604d..29f2c89b 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -230,7 +230,7 @@ const queryClient = new QueryClient({ }); function Layout() { - const [settings] = useSettings(null); + const { settings } = useSettings(); const [user] = useAtom(userAtom); const [api] = useAtom(apiAtom); const appState = useRef(AppState.currentState); diff --git a/components/DownloadItem.tsx b/components/DownloadItem.tsx index eb1710a3..60a248c7 100644 --- a/components/DownloadItem.tsx +++ b/components/DownloadItem.tsx @@ -61,7 +61,7 @@ export const DownloadItems: React.FC = ({ const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); const [queue, _setQueue] = useAtom(queueAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); const [downloadUnwatchedOnly, setDownloadUnwatchedOnly] = useState(false); const { processes, startBackgroundDownload, getDownloadedItems } = diff --git a/components/ItemContent.tsx b/components/ItemContent.tsx index c49049f8..6c91a530 100644 --- a/components/ItemContent.tsx +++ b/components/ItemContent.tsx @@ -54,7 +54,7 @@ interface ItemContentProps { export const ItemContent: React.FC = React.memo( ({ item, isOffline }) => { const [api] = useAtom(apiAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); const { orientation } = useOrientation(); const navigation = useNavigation(); const insets = useSafeAreaInsets(); diff --git a/components/PlayButton.tsx b/components/PlayButton.tsx index 932cf51d..3f4ca141 100644 --- a/components/PlayButton.tsx +++ b/components/PlayButton.tsx @@ -67,7 +67,7 @@ export const PlayButton: React.FC = ({ const startColor = useSharedValue(colorAtom); const widthProgress = useSharedValue(0); const colorChangeProgress = useSharedValue(0); - const [settings, updateSettings] = useSettings(null); + const { settings, updateSettings } = useSettings(); const lightHapticFeedback = useHaptic("light"); const goToPlayer = useCallback( diff --git a/components/PlayButton.tv.tsx b/components/PlayButton.tv.tsx index c9443cc6..b4fa45a9 100644 --- a/components/PlayButton.tv.tsx +++ b/components/PlayButton.tv.tsx @@ -44,7 +44,7 @@ export const PlayButton: React.FC = ({ const startColor = useSharedValue(colorAtom); const widthProgress = useSharedValue(0); const colorChangeProgress = useSharedValue(0); - const [settings] = useSettings(null); + const { settings } = useSettings(); const lightHapticFeedback = useHaptic("light"); const goToPlayer = useCallback( diff --git a/components/common/JellyseerrItemRouter.tsx b/components/common/JellyseerrItemRouter.tsx index d9a039eb..89b7d2f2 100644 --- a/components/common/JellyseerrItemRouter.tsx +++ b/components/common/JellyseerrItemRouter.tsx @@ -10,6 +10,7 @@ import { Permission, } from "@/utils/jellyseerr/server/lib/permissions"; import type { MovieDetails } from "@/utils/jellyseerr/server/models/Movie"; +import { PersonCreditCast } from "@/utils/jellyseerr/server/models/Person"; import type { MovieResult, TvResult, @@ -17,7 +18,7 @@ import type { import type { TvDetails } from "@/utils/jellyseerr/server/models/Tv"; interface Props extends TouchableOpacityProps { - result?: MovieResult | TvResult | MovieDetails | TvDetails; + result?: MovieResult | TvResult | MovieDetails | TvDetails | PersonCreditCast; mediaTitle: string; releaseYear: number; canRequest: boolean; diff --git a/components/home/LargeMovieCarousel.tsx b/components/home/LargeMovieCarousel.tsx index de1d7de2..375059d0 100644 --- a/components/home/LargeMovieCarousel.tsx +++ b/components/home/LargeMovieCarousel.tsx @@ -26,7 +26,7 @@ import { itemRouter } from "../common/TouchableItemRouter"; interface Props extends ViewProps {} export const LargeMovieCarousel: React.FC = ({ ...props }) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const ref = React.useRef(null); const progress = useSharedValue(0); diff --git a/components/jellyseerr/discover/MovieTvSlide.tsx b/components/jellyseerr/discover/MovieTvSlide.tsx index 38974b5f..a82f48a3 100644 --- a/components/jellyseerr/discover/MovieTvSlide.tsx +++ b/components/jellyseerr/discover/MovieTvSlide.tsx @@ -11,16 +11,12 @@ import { useJellyseerr, } from "@/hooks/useJellyseerr"; import { DiscoverSliderType } from "@/utils/jellyseerr/server/constants/discover"; -import type { - MovieResult, - TvResult, -} from "@/utils/jellyseerr/server/models/Search"; const MovieTvSlide: React.FC = ({ slide, ...props }) => { - const { jellyseerrApi } = useJellyseerr(); + const { jellyseerrApi, isJellyseerrMovieOrTvResult } = useJellyseerr(); const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({ queryKey: ["jellyseerr", "discover", slide.id], @@ -69,7 +65,9 @@ const MovieTvSlide: React.FC = ({ uniqBy( data?.pages ?.filter((p) => p?.results.length) - .flatMap((p) => p?.results), + .flatMap((p) => + p?.results.filter((r) => isJellyseerrMovieOrTvResult(r)), + ), "id", ), [data], @@ -86,12 +84,7 @@ const MovieTvSlide: React.FC = ({ onEndReached={() => { if (hasNextPage) fetchNextPage(); }} - renderItem={(item) => ( - - )} + renderItem={(item) => } /> ) ); diff --git a/components/library/LibraryItemCard.tsx b/components/library/LibraryItemCard.tsx index f7d3fb9b..efb29013 100644 --- a/components/library/LibraryItemCard.tsx +++ b/components/library/LibraryItemCard.tsx @@ -41,7 +41,7 @@ const icons: Record = { export const LibraryItemCard: React.FC = ({ library, ...props }) => { const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); const { t } = useTranslation(); diff --git a/components/posters/JellyseerrPoster.tsx b/components/posters/JellyseerrPoster.tsx index 49605078..d7b1fcdb 100644 --- a/components/posters/JellyseerrPoster.tsx +++ b/components/posters/JellyseerrPoster.tsx @@ -20,6 +20,7 @@ import { MediaStatus } from "@/utils/jellyseerr/server/constants/media"; import type MediaRequest from "@/utils/jellyseerr/server/entity/MediaRequest"; import type { DownloadingItem } from "@/utils/jellyseerr/server/lib/downloadtracker"; import type { MovieDetails } from "@/utils/jellyseerr/server/models/Movie"; +import { PersonCreditCast } from "@/utils/jellyseerr/server/models/Person"; import type { MovieResult, TvResult, @@ -27,7 +28,7 @@ import type { import type { TvDetails } from "@/utils/jellyseerr/server/models/Tv"; interface Props extends ViewProps { - item?: MovieResult | TvResult | MovieDetails | TvDetails; + item?: MovieResult | TvResult | MovieDetails | TvDetails | PersonCreditCast; horizontal?: boolean; showDownloadInfo?: boolean; mediaRequest?: MediaRequest; diff --git a/components/settings/AppLanguageSelector.tsx b/components/settings/AppLanguageSelector.tsx index 42d68929..f77bc2c8 100644 --- a/components/settings/AppLanguageSelector.tsx +++ b/components/settings/AppLanguageSelector.tsx @@ -12,7 +12,7 @@ interface Props extends ViewProps {} export const AppLanguageSelector: React.FC = () => { const isTv = Platform.isTV; - const [settings, updateSettings] = useSettings(null); + const { settings, updateSettings } = useSettings(); const { t } = useTranslation(); if (isTv) return null; diff --git a/components/settings/AudioToggles.tsx b/components/settings/AudioToggles.tsx index 29f851c9..82ff1157 100644 --- a/components/settings/AudioToggles.tsx +++ b/components/settings/AudioToggles.tsx @@ -17,7 +17,7 @@ export const AudioToggles: React.FC = ({ ...props }) => { const isTv = Platform.isTV; const media = useMedia(); - const [_, __, pluginSettings] = useSettings(null); + const { pluginSettings } = useSettings(); const { settings, updateSettings } = media; const cultures = media.cultures; const { t } = useTranslation(); diff --git a/components/settings/ChromecastSettings.tsx b/components/settings/ChromecastSettings.tsx index 096da489..4da06332 100644 --- a/components/settings/ChromecastSettings.tsx +++ b/components/settings/ChromecastSettings.tsx @@ -4,7 +4,7 @@ import { ListGroup } from "../list/ListGroup"; import { ListItem } from "../list/ListItem"; export const ChromecastSettings: React.FC = ({ ...props }) => { - const [settings, updateSettings] = useSettings(null); + const { settings, updateSettings } = useSettings(); return ( diff --git a/components/settings/Dashboard.tsx b/components/settings/Dashboard.tsx index 0404f535..768c6e0b 100644 --- a/components/settings/Dashboard.tsx +++ b/components/settings/Dashboard.tsx @@ -7,7 +7,7 @@ import { ListGroup } from "../list/ListGroup"; import { ListItem } from "../list/ListItem"; export const Dashboard = () => { - const [settings, _updateSettings] = useSettings(null); + const { settings } = useSettings(); const { sessions = [] } = useSessions({} as useSessionsProps); const router = useRouter(); diff --git a/components/settings/DownloadSettings.tsx b/components/settings/DownloadSettings.tsx index 3d609610..483d895b 100644 --- a/components/settings/DownloadSettings.tsx +++ b/components/settings/DownloadSettings.tsx @@ -7,7 +7,7 @@ import { ListGroup } from "../list/ListGroup"; import { ListItem } from "../list/ListItem"; export default function DownloadSettings({ ...props }) { - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const { t } = useTranslation(); const allDisabled = useMemo( diff --git a/components/settings/GestureControls.tsx b/components/settings/GestureControls.tsx index bb77af99..55aadaa1 100644 --- a/components/settings/GestureControls.tsx +++ b/components/settings/GestureControls.tsx @@ -13,7 +13,7 @@ interface Props extends ViewProps {} export const GestureControls: React.FC = ({ ...props }) => { const { t } = useTranslation(); - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const disabled = useMemo( () => diff --git a/components/settings/HomeIndex.tsx b/components/settings/HomeIndex.tsx index 5278c17f..75215461 100644 --- a/components/settings/HomeIndex.tsx +++ b/components/settings/HomeIndex.tsx @@ -64,13 +64,7 @@ export const HomeIndex = () => { const user = useAtomValue(userAtom); const [loading, setLoading] = useState(false); - const [ - settings, - _updateSettings, - _pluginSettings, - _setPluginSettings, - refreshStreamyfinPluginSettings, - ] = useSettings(null); + const { settings, refreshStreamyfinPluginSettings } = useSettings(); const navigation = useNavigation(); diff --git a/components/settings/Jellyseerr.tsx b/components/settings/Jellyseerr.tsx index 87a99964..470d40a2 100644 --- a/components/settings/Jellyseerr.tsx +++ b/components/settings/Jellyseerr.tsx @@ -20,7 +20,7 @@ export const JellyseerrSettings = () => { const { t } = useTranslation(); const [user] = useAtom(userAtom); - const [settings, updateSettings, _pluginSettings] = useSettings(null); + const { settings, updateSettings } = useSettings(); const [jellyseerrPassword, setJellyseerrPassword] = useState< string | undefined diff --git a/components/settings/MediaContext.tsx b/components/settings/MediaContext.tsx index 4f363694..c6c7856e 100644 --- a/components/settings/MediaContext.tsx +++ b/components/settings/MediaContext.tsx @@ -28,7 +28,7 @@ export const useMedia = () => { }; export const MediaProvider = ({ children }: { children: ReactNode }) => { - const [settings, updateSettings] = useSettings(null); + const { settings, updateSettings } = useSettings(); const api = useAtomValue(apiAtom); const queryClient = useQueryClient(); diff --git a/components/settings/MediaToggles.tsx b/components/settings/MediaToggles.tsx index 1715446a..c01a6d13 100644 --- a/components/settings/MediaToggles.tsx +++ b/components/settings/MediaToggles.tsx @@ -13,7 +13,7 @@ interface Props extends ViewProps {} export const MediaToggles: React.FC = ({ ...props }) => { const { t } = useTranslation(); - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const disabled = useMemo( () => diff --git a/components/settings/OtherSettings.tsx b/components/settings/OtherSettings.tsx index cfeb10f7..e0ca1147 100644 --- a/components/settings/OtherSettings.tsx +++ b/components/settings/OtherSettings.tsx @@ -23,7 +23,7 @@ import { ListItem } from "../list/ListItem"; export const OtherSettings: React.FC = () => { const router = useRouter(); - const [settings, updateSettings, pluginSettings] = useSettings(null); + const { settings, updateSettings, pluginSettings } = useSettings(); const { t } = useTranslation(); diff --git a/components/settings/PluginSettings.tsx b/components/settings/PluginSettings.tsx index c830f9e3..9d8c64dd 100644 --- a/components/settings/PluginSettings.tsx +++ b/components/settings/PluginSettings.tsx @@ -6,7 +6,7 @@ import { ListGroup } from "../list/ListGroup"; import { ListItem } from "../list/ListItem"; export const PluginSettings = () => { - const [settings, _updateSettings] = useSettings(null); + const { settings } = useSettings(); const router = useRouter(); diff --git a/components/settings/SubtitleToggles.tsx b/components/settings/SubtitleToggles.tsx index 60cd96e7..59ec1570 100644 --- a/components/settings/SubtitleToggles.tsx +++ b/components/settings/SubtitleToggles.tsx @@ -20,7 +20,7 @@ export const SubtitleToggles: React.FC = ({ ...props }) => { const isTv = Platform.isTV; const media = useMedia(); - const [_, __, pluginSettings] = useSettings(null); + const { pluginSettings } = useSettings(); const { settings, updateSettings } = media; const cultures = media.cultures; const { t } = useTranslation(); diff --git a/components/video-player/controls/BottomControls.tsx b/components/video-player/controls/BottomControls.tsx index 3ff5987b..59da6f7b 100644 --- a/components/video-player/controls/BottomControls.tsx +++ b/components/video-player/controls/BottomControls.tsx @@ -88,7 +88,7 @@ export const BottomControls: FC = ({ trickplayInfo, time, }) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const insets = useSafeAreaInsets(); return ( diff --git a/components/video-player/controls/CenterControls.tsx b/components/video-player/controls/CenterControls.tsx index b00d9333..47659746 100644 --- a/components/video-player/controls/CenterControls.tsx +++ b/components/video-player/controls/CenterControls.tsx @@ -30,7 +30,7 @@ export const CenterControls: FC = ({ handleSkipBackward, handleSkipForward, }) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const insets = useSafeAreaInsets(); return ( diff --git a/components/video-player/controls/ContinueWatchingOverlay.tsx b/components/video-player/controls/ContinueWatchingOverlay.tsx index 829c4d83..4c353dee 100644 --- a/components/video-player/controls/ContinueWatchingOverlay.tsx +++ b/components/video-player/controls/ContinueWatchingOverlay.tsx @@ -16,7 +16,7 @@ export interface ContinueWatchingOverlayProps { const ContinueWatchingOverlay: React.FC = ({ goToNextItem, }) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const router = useRouter(); return settings.autoPlayEpisodeCount >= diff --git a/components/video-player/controls/Controls.tsx b/components/video-player/controls/Controls.tsx index 7ca768af..fee1a7de 100644 --- a/components/video-player/controls/Controls.tsx +++ b/components/video-player/controls/Controls.tsx @@ -116,7 +116,7 @@ export const Controls: FC = ({ api = null, downloadedFiles = undefined, }) => { - const [settings, updateSettings] = useSettings(api); + const { settings, updateSettings } = useSettings(); const router = useRouter(); const lightHapticFeedback = useHaptic("light"); diff --git a/components/video-player/controls/GestureOverlay.tsx b/components/video-player/controls/GestureOverlay.tsx index 1f6fe0ad..e4ca20e6 100644 --- a/components/video-player/controls/GestureOverlay.tsx +++ b/components/video-player/controls/GestureOverlay.tsx @@ -31,7 +31,7 @@ export const GestureOverlay = ({ onSkipForward, onSkipBackward, }: Props) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const lightHaptic = useHaptic("light"); const [feedback, setFeedback] = useState({ diff --git a/components/video-player/controls/HeaderControls.tsx b/components/video-player/controls/HeaderControls.tsx index 534e366d..07232014 100644 --- a/components/video-player/controls/HeaderControls.tsx +++ b/components/video-player/controls/HeaderControls.tsx @@ -70,7 +70,7 @@ export const HeaderControls: FC = ({ setVideoAspectRatio, setVideoScaleFactor, }) => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const router = useRouter(); const insets = useSafeAreaInsets(); const { width: screenWidth } = useWindowDimensions(); diff --git a/components/video-player/controls/hooks/useVideoNavigation.ts b/components/video-player/controls/hooks/useVideoNavigation.ts index 524bdd7f..0573d6e4 100644 --- a/components/video-player/controls/hooks/useVideoNavigation.ts +++ b/components/video-player/controls/hooks/useVideoNavigation.ts @@ -20,7 +20,7 @@ export function useVideoNavigation({ seek, play, }: UseVideoNavigationProps) { - const [settings] = useSettings(null); + const { settings } = useSettings(); const lightHapticFeedback = useHaptic("light"); const wasPlayingRef = useRef(false); diff --git a/hooks/useHaptic.ts b/hooks/useHaptic.ts index 8afeffcf..42ae274e 100644 --- a/hooks/useHaptic.ts +++ b/hooks/useHaptic.ts @@ -14,7 +14,7 @@ export type HapticFeedbackType = | "error"; export const useHaptic = (feedbackType: HapticFeedbackType = "selection") => { - const [settings] = useSettings(null); + const { settings } = useSettings(); const isTv = Platform.isTV; const isDisabled = isTv || diff --git a/hooks/useJellyseerr.ts b/hooks/useJellyseerr.ts index cb1ee376..6add563e 100644 --- a/hooks/useJellyseerr.ts +++ b/hooks/useJellyseerr.ts @@ -14,7 +14,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { t } from "i18next"; import { useCallback, useMemo } from "react"; import { toast } from "sonner-native"; -import { defaultValues, Settings } from "@/utils/atoms/settings"; +import { useSettings } from "@/utils/atoms/settings"; import type { RTRating } from "@/utils/jellyseerr/server/api/rating/rottentomatoes"; import { IssueStatus, @@ -40,6 +40,7 @@ import type { UserResultsResponse } from "@/utils/jellyseerr/server/interfaces/a import type { MovieDetails } from "@/utils/jellyseerr/server/models/Movie"; import type { CombinedCredit, + PersonCreditCast, PersonDetails, } from "@/utils/jellyseerr/server/models/Person"; import type { @@ -416,10 +417,8 @@ export class JellyseerrApi { const jellyseerrUserAtom = atom(storage.get(JELLYSEERR_USER)); -export const useJellyseerr = ( - settings: Settings = defaultValues, - updateSettings: (update: Partial) => void = () => {}, -) => { +export const useJellyseerr = () => { + const { settings, updateSettings } = useSettings(); const [jellyseerrUser, setJellyseerrUser] = useAtom(jellyseerrUserAtom); const queryClient = useQueryClient(); @@ -468,49 +467,47 @@ export const useJellyseerr = ( [jellyseerrApi], ); - const isJellyseerrResult = ( + const isJellyseerrMovieOrTvResult = ( items: any | null | undefined, - ): items is Results => { + ): items is MovieResult | TvResult => { return ( items && Object.hasOwn(items, "mediaType") && - Object.values(MediaType).includes(items.mediaType as MediaType) + (items.mediaType === MediaType.MOVIE || items.mediaType === MediaType.TV) ); }; const getTitle = ( - item?: TvResult | TvDetails | MovieResult | MovieDetails, + item?: TvResult | TvDetails | MovieResult | MovieDetails | PersonCreditCast, ) => { - return isJellyseerrResult(item) + return isJellyseerrMovieOrTvResult(item) ? item.mediaType === MediaType.MOVIE ? item?.title : item?.name - : item?.mediaInfo.mediaType === MediaType.MOVIE + : item?.mediaInfo?.mediaType === MediaType.MOVIE ? (item as MovieDetails)?.title : (item as TvDetails)?.name; }; const getYear = ( - item?: TvResult | TvDetails | MovieResult | MovieDetails, + item?: TvResult | TvDetails | MovieResult | MovieDetails | PersonCreditCast, ) => { return new Date( - (isJellyseerrResult(item) + (isJellyseerrMovieOrTvResult(item) ? item.mediaType === MediaType.MOVIE ? item?.releaseDate : item?.firstAirDate - : item?.mediaInfo.mediaType === MediaType.MOVIE + : item?.mediaInfo?.mediaType === MediaType.MOVIE ? (item as MovieDetails)?.releaseDate : (item as TvDetails)?.firstAirDate) || "", )?.getFullYear?.(); }; const getMediaType = ( - item?: TvResult | TvDetails | MovieResult | MovieDetails, + item?: TvResult | TvDetails | MovieResult | MovieDetails | PersonCreditCast, ): MediaType => { - return isJellyseerrResult(item) - ? item.mediaType === "movie" - ? MediaType.MOVIE - : MediaType.TV + return isJellyseerrMovieOrTvResult(item) + ? (item.mediaType as MediaType) : item?.mediaInfo?.mediaType; }; @@ -528,7 +525,7 @@ export const useJellyseerr = ( jellyseerrUser, setJellyseerrUser, clearAllJellyseerData, - isJellyseerrResult, + isJellyseerrMovieOrTvResult, getTitle, getYear, getMediaType, diff --git a/providers/DownloadProvider.tsx b/providers/DownloadProvider.tsx index 7b76d934..7a8fe7d1 100644 --- a/providers/DownloadProvider.tsx +++ b/providers/DownloadProvider.tsx @@ -87,7 +87,7 @@ function useDownloadProvider() { const { saveSeriesPrimaryImage } = useDownloadHelper(); const { saveImage } = useImageStorage(); const [processes, setProcesses] = useAtom(processesAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); const successHapticFeedback = useHaptic("success"); /// Cant use the background downloader callback. As its not triggered if size is unknown. diff --git a/providers/JellyfinProvider.tsx b/providers/JellyfinProvider.tsx index 8b4d0728..56f64abd 100644 --- a/providers/JellyfinProvider.tsx +++ b/providers/JellyfinProvider.tsx @@ -79,17 +79,8 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ const [user, setUser] = useAtom(userAtom); const [isPolling, setIsPolling] = useState(false); const [secret, setSecret] = useState(null); - const [ - _settings, - _updateSettings, - _pluginSettings, - setPluginSettings, - refreshStreamyfinPluginSettings, - ] = useSettings(api); - const { clearAllJellyseerData, setJellyseerrUser } = useJellyseerr( - _settings || {}, - _updateSettings, - ); + const { setPluginSettings, refreshStreamyfinPluginSettings } = useSettings(); + const { clearAllJellyseerData, setJellyseerrUser } = useJellyseerr(); const headers = useMemo(() => { if (!deviceId) return {}; diff --git a/utils/_jellyseerr/useJellyseerrCanRequest.ts b/utils/_jellyseerr/useJellyseerrCanRequest.ts index c8872769..2cd67a33 100644 --- a/utils/_jellyseerr/useJellyseerrCanRequest.ts +++ b/utils/_jellyseerr/useJellyseerrCanRequest.ts @@ -9,6 +9,7 @@ import { hasPermission, Permission, } from "@/utils/jellyseerr/server/lib/permissions"; +import { PersonCreditCast } from "@/utils/jellyseerr/server/models/Person"; import type { MovieResult, TvResult, @@ -18,7 +19,7 @@ import type { MovieDetails } from "../jellyseerr/server/models/Movie"; import type { TvDetails } from "../jellyseerr/server/models/Tv"; export const useJellyseerrCanRequest = ( - item?: MovieResult | TvResult | MovieDetails | TvDetails, + item?: MovieResult | TvResult | MovieDetails | TvDetails | PersonCreditCast, ) => { const { jellyseerrUser } = useJellyseerr(); diff --git a/utils/atoms/queue.ts b/utils/atoms/queue.ts index 516b951f..3b787e22 100644 --- a/utils/atoms/queue.ts +++ b/utils/atoms/queue.ts @@ -56,7 +56,7 @@ export const useJobProcessor = () => { const [queue, setQueue] = useAtom(queueAtom); const [running, setRunning] = useAtom(runningAtom); const [processes] = useAtom(processesAtom); - const [settings] = useSettings(null); + const { settings } = useSettings(); useEffect(() => { if ( diff --git a/utils/atoms/settings.ts b/utils/atoms/settings.ts index 40e4b022..d24114c5 100644 --- a/utils/atoms/settings.ts +++ b/utils/atoms/settings.ts @@ -1,4 +1,3 @@ -import type { Api } from "@jellyfin/sdk"; import { type BaseItemKind, type CultureDto, @@ -7,11 +6,12 @@ import { type SortOrder, SubtitlePlaybackMode, } from "@jellyfin/sdk/lib/generated-client"; -import { atom, useAtom } from "jotai"; +import { atom, useAtom, useAtomValue } from "jotai"; import { useCallback, useEffect, useMemo } from "react"; import { Platform } from "react-native"; import { BITRATES, type Bitrate } from "@/components/BitrateSelector"; import * as ScreenOrientation from "@/packages/expo-screen-orientation"; +import { apiAtom } from "@/providers/JellyfinProvider"; import { writeInfoLog } from "@/utils/log"; import { storage } from "../mmkv"; @@ -278,7 +278,8 @@ export const pluginSettingsAtom = atom( loadPluginSettings(), ); -export const useSettings = (api: Api | null) => { +export const useSettings = () => { + const api = useAtomValue(apiAtom); const [_settings, setSettings] = useAtom(settingsAtom); const [pluginSettings, _setPluginSettings] = useAtom(pluginSettingsAtom); @@ -302,11 +303,11 @@ export const useSettings = (api: Api | null) => { return; } const settings = await api.getStreamyfinPluginConfig().then( - ({ data }: any) => { + ({ data }) => { writeInfoLog("Got plugin settings", data?.settings); return data?.settings; }, - (_err: any) => undefined, + (_err) => undefined, ); setPluginSettings(settings); return settings; @@ -367,11 +368,11 @@ export const useSettings = (api: Api | null) => { }; }, [_settings, pluginSettings]); - return [ + return { settings, updateSettings, pluginSettings, setPluginSettings, refreshStreamyfinPluginSettings, - ] as const; + }; };