Automatically play next ep when skipping end credits

This commit is contained in:
Zoe Roux 2026-04-15 23:26:21 +02:00
parent 62bbaaa9d5
commit 91b83f9596
No known key found for this signature in database
3 changed files with 27 additions and 7 deletions

View File

@ -21,6 +21,7 @@ export const Controls = ({
chapters,
playPrev,
playNext,
seekEnd,
onOpenEntriesMenu,
forceShow,
}: {
@ -34,6 +35,7 @@ export const Controls = ({
chapters: Chapter[];
playPrev: (() => boolean) | null;
playNext: (() => boolean) | null;
seekEnd: () => void;
onOpenEntriesMenu?: () => void;
forceShow?: boolean;
}) => {
@ -98,6 +100,7 @@ export const Controls = ({
player={player}
chapters={chapters}
isVisible={controlsVisible}
seekEnd={seekEnd}
/>
</View>
);

View File

@ -3,18 +3,24 @@ import { useTranslation } from "react-i18next";
import { useEvent, type VideoPlayer } from "react-native-video";
import type { Chapter } from "~/models";
import { Button } from "~/primitives";
import { cn } from "~/utils";
import { useFetch } from "~/query";
import { Info } from "~/ui/info";
import { cn, useQueryState } from "~/utils";
export const SkipChapterButton = ({
player,
seekEnd,
chapters,
isVisible,
}: {
player: VideoPlayer;
seekEnd: () => void;
chapters: Chapter[];
isVisible: boolean;
}) => {
const { t } = useTranslation();
const [slug] = useQueryState<string>("slug", undefined!);
const { data } = useFetch(Info.infoQuery(slug));
const [progress, setProgress] = useState(player.currentTime || 0);
useEvent(player, "onProgress", ({ currentTime }) => {
@ -27,12 +33,21 @@ export const SkipChapterButton = ({
if (!chapter || chapter.type === "content") return null;
if (!isVisible && progress >= chapter.startTime + 8) return null;
// delay credits appearance by a few seconds, we want to make sure it doesn't
// show on top of the end of the serie. it's common for the end credits music
// to start playing on top of the episode also.
const start = chapter.startTime + +(chapter.type === "credits") * 4;
if (!isVisible && progress >= start + 8) return null;
return (
<Button
text={t(`player.skip-${chapter.type}`)}
onPress={() => player.seekTo(chapter.endTime)}
onPress={() => {
if (data?.durationSeconds && data.durationSeconds <= chapter.endTime) {
return seekEnd();
}
player.seekTo(chapter.endTime);
}}
className={cn(
"absolute right-safe bottom-2/10 m-8",
"z-20 bg-slate-900/70 px-4 py-2",

View File

@ -139,6 +139,10 @@ export const Player = () => {
setSlug(data.next.video);
return true;
}, [data?.next, setSlug, setStart, t]);
const onEnd = useCallback(() => {
const hasNext = playNext();
if (!hasNext && data?.show?.href) router.navigate(data.show.href);
}, [data?.show?.href, playNext, router]);
useProgressObserver(
player,
@ -146,10 +150,7 @@ export const Player = () => {
);
useLanguagePreference(player, slug);
useEvent(player, "onEnd", () => {
const hasNext = playNext();
if (!hasNext && data?.show) router.navigate(data.show.href);
});
useEvent(player, "onEnd", onEnd);
// TODO: add the equivalent of this for android
useEffect(() => {
@ -225,6 +226,7 @@ export const Player = () => {
chapters={info?.chapters ?? []}
playPrev={data?.previous ? playPrev : null}
playNext={data?.next ? playNext : null}
seekEnd={onEnd}
onOpenEntriesMenu={
data?.show?.kind === "serie"
? () => setEntriesMenuOpen(true)