diff --git a/components/CurrentlyPlayingBar.tsx b/components/CurrentlyPlayingBar.tsx index 18052080..691d3bda 100644 --- a/components/CurrentlyPlayingBar.tsx +++ b/components/CurrentlyPlayingBar.tsx @@ -4,7 +4,7 @@ import { useNavigationBarVisibility } from "@/hooks/useNavigationBarVisibility"; import { useTrickplay } from "@/hooks/useTrickplay"; import { apiAtom } from "@/providers/JellyfinProvider"; import { usePlayback } from "@/providers/PlaybackProvider"; -import { parseM3U8ForSubtitles } from "@/utils/hls/parseM3U8ForSubtitles"; +import { useSettings } from "@/utils/atoms/settings"; import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; import { getAuthHeaders } from "@/utils/jellyfin/jellyfin"; import { writeToLog } from "@/utils/log"; @@ -14,6 +14,7 @@ import { Ionicons } from "@expo/vector-icons"; import { useQuery } from "@tanstack/react-query"; import { Image } from "expo-image"; import { useRouter, useSegments } from "expo-router"; +import * as ScreenOrientation from "expo-screen-orientation"; import { useAtom } from "jotai"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { @@ -35,8 +36,6 @@ import Video from "react-native-video"; import { Text } from "./common/Text"; import { itemRouter } from "./common/TouchableItemRouter"; import { Loader } from "./Loader"; -import * as ScreenOrientation from "expo-screen-orientation"; -import { useSettings } from "@/utils/atoms/settings"; async function setOrientation(orientation: ScreenOrientation.OrientationLock) { await ScreenOrientation.lockAsync(orientation); @@ -145,16 +144,19 @@ export const CurrentlyPlayingBar: React.FC = () => { max.value = currentlyPlaying?.item.RunTimeTicks || 0; }, [currentlyPlaying?.item.RunTimeTicks]); - const videoContainerStyle = { - position: "absolute" as const, - top: 0, - bottom: 0, - left: ignoreSafeArea ? 0 : insets.left, - right: ignoreSafeArea ? 0 : insets.right, - width: ignoreSafeArea - ? screenWidth - : screenWidth - (insets.left + insets.right), - }; + const videoContainerStyle = useMemo( + () => ({ + position: "absolute" as const, + top: 0, + bottom: 0, + left: ignoreSafeArea ? 0 : insets.left, + right: ignoreSafeArea ? 0 : insets.right, + width: ignoreSafeArea + ? screenWidth + : screenWidth - (insets.left + insets.right), + }), + [ignoreSafeArea, insets, screenWidth] + ); const animatedLoaderStyle = useAnimatedStyle(() => { return { @@ -226,29 +228,14 @@ export const CurrentlyPlayingBar: React.FC = () => { }); const skipIntro = useCallback(async () => { - if (!introTimestamps) return; - videoRef.current?.seek(introTimestamps.IntroEnd); + if (!introTimestamps || !videoRef.current) return; + try { + videoRef.current.seek(introTimestamps.IntroEnd); + } catch (error) { + writeToLog("ERROR", "Error skipping intro", error); + } }, [introTimestamps]); - useEffect(() => { - showControls(); - }, [currentlyPlaying]); - - const { data: subtitleTracks } = useQuery({ - queryKey: ["subtitleTracks", currentlyPlaying?.url], - queryFn: async () => { - if (!currentlyPlaying?.url) { - console.log("No item url"); - return null; - } - - const tracks = await parseM3U8ForSubtitles(currentlyPlaying.url); - - console.log("Subtitle tracks", tracks); - return tracks; - }, - }); - /** * This should clean up all values if curentlyPlaying sets to null or changes */ @@ -280,6 +267,14 @@ export const CurrentlyPlayingBar: React.FC = () => { } }, [settings, currentlyPlaying]); + const handleToggleControlsPress = useCallback(() => { + if (isVisible) { + hideControls(); + } else { + showControls(); + } + }, [isVisible, hideControls, showControls]); + if (!api || !currentlyPlaying) return null; return ( @@ -292,13 +287,7 @@ export const CurrentlyPlayingBar: React.FC = () => { > { - if (isVisible) { - hideControls(); - } else { - showControls(); - } - }} + onPress={handleToggleControlsPress} style={{ width: "100%", height: "100%", @@ -412,8 +401,8 @@ export const CurrentlyPlayingBar: React.FC = () => { > { - if (!isVisible) return; skipIntro(); }} className="flex flex-col items-center justify-center px-2 py-1.5 bg-purple-600 rounded-full" @@ -436,8 +425,8 @@ export const CurrentlyPlayingBar: React.FC = () => { > { - if (!isVisible) return; toggleIgnoreSafeArea(); }} className="aspect-square rounded flex flex-col items-center justify-center p-2" @@ -449,8 +438,8 @@ export const CurrentlyPlayingBar: React.FC = () => { /> { - if (!isVisible) return; stopPlayback(); }} className="aspect-square rounded flex flex-col items-center justify-center p-2" @@ -493,12 +482,11 @@ export const CurrentlyPlayingBar: React.FC = () => { { - if (!isVisible) return; if (!previousItem || !from) return; const url = itemRouter(previousItem, from); stopPlayback(); @@ -509,12 +497,17 @@ export const CurrentlyPlayingBar: React.FC = () => { { - if (!isVisible) return; - const curr = await videoRef.current?.getCurrentPosition(); - if (!curr) return; - videoRef.current?.seek(Math.max(0, curr - 15)); - showControls(); + try { + const curr = await videoRef.current?.getCurrentPosition(); + if (curr !== undefined) { + videoRef.current?.seek(Math.max(0, curr - 15)); + showControls(); + } + } catch (error) { + writeToLog("ERROR", "Error seeking video backwards", error); + } }} > { /> { - if (!isVisible) return; if (isPlaying) pauseVideo(); else playVideo(); showControls(); @@ -541,23 +534,27 @@ export const CurrentlyPlayingBar: React.FC = () => { /> { - if (!isVisible) return; - const curr = await videoRef.current?.getCurrentPosition(); - if (!curr) return; - videoRef.current?.seek(Math.max(0, curr + 15)); - showControls(); + try { + const curr = await videoRef.current?.getCurrentPosition(); + if (curr !== undefined) { + await videoRef.current?.seek(Math.max(0, curr + 15)); + showControls(); + } + } catch (error) { + writeToLog("ERROR", "Error seeking video forwards", error); + } }} > { - if (!isVisible) return; if (!nextItem || !from) return; const url = itemRouter(nextItem, from); stopPlayback(); @@ -570,6 +567,7 @@ export const CurrentlyPlayingBar: React.FC = () => { { }} cache={cacheProgress} onSlidingStart={() => { - if (!isVisible) return; sliding.current = true; }} onSlidingComplete={(val) => { - if (!isVisible) return; const tick = Math.floor(val); videoRef.current?.seek(tick / 10000000); sliding.current = false; }} onValueChange={(val) => { - if (!isVisible) return; const tick = Math.floor(val); progress.value = tick; calculateTrickplayUrl(progress); diff --git a/hooks/useControlsVisibility.ts b/hooks/useControlsVisibility.ts index 3ccfd0ef..6d829f06 100644 --- a/hooks/useControlsVisibility.ts +++ b/hooks/useControlsVisibility.ts @@ -2,7 +2,9 @@ import { useRef, useCallback, useState, useEffect } from "react"; export const useControlsVisibility = (timeout: number = 3000) => { const [isVisible, setIsVisible] = useState(true); - const hideControlsTimerRef = useRef(null); + const hideControlsTimerRef = useRef | null>( + null + ); const showControls = useCallback(() => { setIsVisible(true); @@ -21,5 +23,13 @@ export const useControlsVisibility = (timeout: number = 3000) => { } }, []); + useEffect(() => { + return () => { + if (hideControlsTimerRef.current) { + clearTimeout(hideControlsTimerRef.current); + } + }; + }, []); + return { isVisible, showControls, hideControls }; };