Skip to content

Commit

Permalink
fix video player crashing on unmount
Browse files Browse the repository at this point in the history
  • Loading branch information
JorrinKievit committed Aug 19, 2024
1 parent 38a6d8f commit 6c5bb84
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 21 deletions.
10 changes: 10 additions & 0 deletions apps/expo/src/app/videoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useEffect } from "react";
import { BackHandler } from "react-native";
import { useLocalSearchParams } from "expo-router";

import type { ScrapeMedia } from "@movie-web/provider-utils";
Expand All @@ -10,6 +12,7 @@ import { PlayerStatus } from "~/stores/player/slices/interface";
import { usePlayerStore } from "~/stores/player/store";

export default function VideoPlayerWrapper() {
const resetVideo = usePlayerStore((state) => state.resetVideo);
const playerStatus = usePlayerStore((state) => state.interface.playerStatus);
const { presentFullscreenPlayer } = usePlayer();

Expand All @@ -31,6 +34,13 @@ export default function VideoPlayerWrapper() {

void presentFullscreenPlayer();

useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", () => {
resetVideo();
return false;
});
}, [resetVideo]);

if (download) {
return <ScraperProcess data={data} download />;
}
Expand Down
3 changes: 3 additions & 0 deletions apps/expo/src/components/player/BackButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import { useRouter } from "expo-router";
import { Ionicons } from "@expo/vector-icons";

import { usePlayer } from "~/hooks/player/usePlayer";
import { usePlayerStore } from "~/stores/player/store";

export const BackButton = () => {
const resetVideo = usePlayerStore((state) => state.resetVideo);
const { dismissFullscreenPlayer } = usePlayer();
const router = useRouter();

return (
<Ionicons
name="arrow-back"
onPress={() => {
resetVideo();
dismissFullscreenPlayer()
.then(() => {
if (router.canGoBack()) {
Expand Down
4 changes: 2 additions & 2 deletions apps/expo/src/components/player/SeekButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export const SeekButton = ({ type }: SeekProps) => {
onPress={() => {
player.currentTime =
type === "forward"
? player.currentTime + 10000
: player.currentTime - 10000;
? player.currentTime + 10
: player.currentTime - 10;
void setAudioPositionAsync(player.currentTime);
}}
/>
Expand Down
63 changes: 46 additions & 17 deletions apps/expo/src/components/player/VideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { VideoPlayer as VideoPlayerType } from "expo-video";
import type { SharedValue } from "react-native-reanimated";
import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo, useState } from "react";
import { Dimensions, Platform } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
Expand All @@ -11,11 +12,12 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ResizeMode } from "expo-av";
import * as Haptics from "expo-haptics";
import { useKeepAwake } from "expo-keep-awake";
import { requireNativeModule } from "expo-modules-core";
import * as NavigationBar from "expo-navigation-bar";
import * as Network from "expo-network";
import { useRouter } from "expo-router";
import * as StatusBar from "expo-status-bar";
import { useVideoPlayer, VideoView } from "expo-video";
import { VideoView } from "expo-video";
import { Feather } from "@expo/vector-icons";
import { Spinner, useTheme, View } from "tamagui";

Expand All @@ -41,6 +43,10 @@ import {
import { CaptionRenderer } from "./CaptionRenderer";
import { ControlsOverlay } from "./ControlsOverlay";

const ExpoVideoPlayer =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
requireNativeModule("ExpoVideo").VideoPlayer as VideoPlayerType;

export const VideoPlayer = () => {
useKeepAwake();

Expand All @@ -60,7 +66,6 @@ export const VideoPlayer = () => {

const scale = useSharedValue(1);

const state = usePlayerStore((state) => state.interface.state);
const isIdle = usePlayerStore((state) => state.interface.isIdle);
const stream = usePlayerStore((state) => state.interface.currentStream);
const selectedAudioTrack = useAudioTrackStore((state) => state.selectedTrack);
Expand All @@ -80,24 +85,43 @@ export const VideoPlayer = () => {
const { wifiDefaultQuality, mobileDataDefaultQuality } =
useNetworkSettingsStore();

const player = useVideoPlayer(videoSrc, (player) => {
if (state === "playing") {
player.play();
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const player: VideoPlayerType = useMemo(
// @ts-expect-error - ExpoVideoPlayer is not a valid component
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
() => new ExpoVideoPlayer(videoSrc),
[videoSrc],
);

useEffect(() => {
if (player) {
setVideoPlayer(player);
}
if (meta) {
}, [player, setVideoPlayer]);

useEffect(() => {
const statusListener = player.addListener("statusChange", (status) => {
console.log("VideoPlayer status", status);
if (status === "readyToPlay") {
player.play();
}
});

return () => {
statusListener.remove();
};
}, [getWatchHistoryItem, meta, player]);

useEffect(() => {
if (meta && player.status === "readyToPlay" && player.currentTime < 1) {
const media = convertMetaToScrapeMedia(meta);
const watchHistoryItem = getWatchHistoryItem(media);
if (watchHistoryItem) {
player.currentTime = watchHistoryItem.positionMillis / 1000;
}
}
});

useEffect(() => {
if (player) {
setVideoPlayer(player);
}
}, [player, setVideoPlayer]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [player.status]);

const updateResizeMode = (newMode: ResizeMode) => {
setResizeMode(newMode);
Expand Down Expand Up @@ -219,12 +243,13 @@ export const VideoPlayer = () => {

return () => {
if (meta) {
// const item = convertMetaToItemData(meta);
// const scrapeMedia = convertMetaToScrapeMedia(meta);
// updateWatchHistory(item, scrapeMedia, player.currentTime);
const item = convertMetaToItemData(meta);
const scrapeMedia = convertMetaToScrapeMedia(meta);
updateWatchHistory(item, scrapeMedia, player.currentTime);
}
void synchronizePlayback();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
isLocalFile,
dismissFullscreenPlayer,
Expand All @@ -241,6 +266,10 @@ export const VideoPlayer = () => {

useEffect(() => {
const playerStatusChange = player.addListener("statusChange", (status) => {
if (status === "readyToPlay") {
player.play();
}

const isFinished = player.duration - player.currentTime < 1;
if (meta && status === "idle" && meta.type === "movie" && isFinished) {
const item = convertMetaToItemData(meta);
Expand Down
12 changes: 10 additions & 2 deletions apps/expo/src/stores/player/slices/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,17 @@ export const createVideoSlice: MakeSlice<VideoSlice> = (set) => ({
set({ isLocalFile });
},
resetVideo() {
set({ meta: null, isLocalFile: false });
set((s) => {
s.interface.playerStatus = PlayerStatus.SCRAPING;
s.player?.release();
return {
meta: null,
isLocalFile: false,
videoSrc: null,
player: null,
interface: {
playerStatus: PlayerStatus.SCRAPING,
},
};
});
},
});

0 comments on commit 6c5bb84

Please sign in to comment.