feat: select skip/rewind time + refactor video player

This commit is contained in:
Fredrik Burmester
2024-09-22 23:05:13 +02:00
parent a023c91877
commit ff1decfe2c
6 changed files with 545 additions and 605 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,8 @@ interface Props extends ViewProps {}
export const MediaToggles: React.FC<Props> = ({ ...props }) => {
const [settings, updateSettings] = useSettings();
if (!settings) return null;
return (
<View>
<Text className="text-lg font-bold mb-2">Media</Text>
@@ -119,6 +121,82 @@ export const MediaToggles: React.FC<Props> = ({ ...props }) => {
</DropdownMenu.Content>
</DropdownMenu.Root>
</View>
<View
className={`
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Forward skip length</Text>
<Text className="text-xs opacity-50">
Choose length in seconds when skipping in video playback.
</Text>
</View>
<View className="flex flex-row items-center">
<TouchableOpacity
onPress={() =>
updateSettings({
forwardSkipTime: Math.max(0, settings.forwardSkipTime - 5),
})
}
className="w-8 h-8 bg-neutral-800 rounded-l-lg flex items-center justify-center"
>
<Text>-</Text>
</TouchableOpacity>
<Text className="bg-neutral-800 first-letter:px-3 py-2 flex items-center justify-center">
{settings.forwardSkipTime}s
</Text>
<TouchableOpacity
className="w-8 h-8 bg-neutral-800 rounded-r-lg flex items-center justify-center"
onPress={() =>
updateSettings({
forwardSkipTime: Math.min(60, settings.forwardSkipTime + 5),
})
}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
<View
className={`
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
`}
>
<View className="flex flex-col shrink">
<Text className="font-semibold">Rewind length</Text>
<Text className="text-xs opacity-50">
Choose length in seconds when skipping in video playback.
</Text>
</View>
<View className="flex flex-row items-center">
<TouchableOpacity
onPress={() =>
updateSettings({
rewindSkipTime: Math.max(0, settings.rewindSkipTime - 5),
})
}
className="w-8 h-8 bg-neutral-800 rounded-l-lg flex items-center justify-center"
>
<Text>-</Text>
</TouchableOpacity>
<Text className="bg-neutral-800 first-letter:px-3 py-2 flex items-center justify-center">
{settings.rewindSkipTime}s
</Text>
<TouchableOpacity
className="w-8 h-8 bg-neutral-800 rounded-r-lg flex items-center justify-center"
onPress={() =>
updateSettings({
rewindSkipTime: Math.min(60, settings.rewindSkipTime + 5),
})
}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
);

View File

@@ -34,7 +34,7 @@ export const useTrickplay = (
const [api] = useAtom(apiAtom);
const [trickPlayUrl, setTrickPlayUrl] = useState<TrickplayUrl | null>(null);
const lastCalculationTime = useRef(0);
const throttleDelay = 100; // 200ms throttle
const throttleDelay = 200; // 200ms throttle
const trickplayInfo = useMemo(() => {
if (!currentlyPlaying?.item.Id || !currentlyPlaying?.item.Trickplay) {
@@ -62,7 +62,7 @@ export const useTrickplay = (
}, [currentlyPlaying]);
const calculateTrickplayUrl = useCallback(
(progress: SharedValue<number>) => {
(progress: number) => {
const now = Date.now();
if (now - lastCalculationTime.current < throttleDelay) {
return null;
@@ -80,7 +80,7 @@ export const useTrickplay = (
throw new Error("Invalid trickplay data");
}
const currentSecond = Math.max(0, Math.floor(progress.value / 10000000));
const currentSecond = Math.max(0, Math.floor(progress / 10000000));
const cols = TileWidth;
const rows = TileHeight;

View File

@@ -70,6 +70,8 @@ type Settings = {
defaultAudioLanguage: DefaultLanguageOption | null;
showHomeTitles: boolean;
defaultVideoOrientation: ScreenOrientation.OrientationLock;
forwardSkipTime: number;
rewindSkipTime: number;
};
/**
@@ -103,6 +105,8 @@ const loadSettings = async (): Promise<Settings> => {
defaultSubtitleLanguage: null,
showHomeTitles: true,
defaultVideoOrientation: ScreenOrientation.OrientationLock.DEFAULT,
forwardSkipTime: 30,
rewindSkipTime: 10,
};
try {

View File

@@ -1,6 +1,5 @@
// seconds to ticks util
export function secondsToTicks(seconds: number): number {
"worklet";
return seconds * 10000000;
}

View File

@@ -6,7 +6,7 @@
* @returns A string formatted as "Xh Ym" where X is hours and Y is minutes.
*/
export const runtimeTicksToMinutes = (
ticks: number | null | undefined,
ticks: number | null | undefined
): string => {
if (!ticks) return "0h 0m";
@@ -20,7 +20,7 @@ export const runtimeTicksToMinutes = (
};
export const runtimeTicksToSeconds = (
ticks: number | null | undefined,
ticks: number | null | undefined
): string => {
if (!ticks) return "0h 0m";
@@ -34,3 +34,37 @@ export const runtimeTicksToSeconds = (
if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
else return `${minutes}m ${seconds}s`;
};
export const formatTimeString = (
t: number | null | undefined,
tick = false
): string => {
if (t === null || t === undefined) return "0:00";
let seconds = t;
if (tick) {
seconds = Math.floor(t / 10000000); // Convert ticks to seconds
}
if (seconds < 0) return "0:00";
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = Math.floor(seconds % 60);
if (hours > 0) {
return `${hours}h ${minutes}m ${remainingSeconds}s`;
} else {
return `${minutes}m ${remainingSeconds}s`;
}
};
export const secondsToTicks = (seconds?: number | undefined) => {
if (!seconds) return 0;
return seconds * 10000000;
};
export const ticksToSeconds = (ticks?: number | undefined) => {
if (!ticks) return 0;
return ticks / 10000000;
};