fix: start position and errors

This commit is contained in:
Fredrik Burmester
2024-10-16 18:58:45 +02:00
parent 6a4fe83fbb
commit ac4ce2934c
5 changed files with 71 additions and 19 deletions

View File

@@ -15,14 +15,21 @@ import {
usePlaySettings,
} from "@/providers/PlaySettingsProvider";
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
import { writeToLog } from "@/utils/log";
import { msToTicks, ticksToMs } from "@/utils/time";
import { Api } from "@jellyfin/sdk";
import { getPlaystateApi } from "@jellyfin/sdk/lib/utils/api";
import * as Haptics from "expo-haptics";
import { useFocusEffect } from "expo-router";
import { useFocusEffect, useRouter } from "expo-router";
import { useAtomValue } from "jotai";
import React, { useCallback, useMemo, useRef, useState } from "react";
import { Dimensions, Pressable, StatusBar, View } from "react-native";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { Alert, Dimensions, Pressable, StatusBar, View } from "react-native";
import { useSharedValue } from "react-native-reanimated";
export default function page() {
@@ -33,6 +40,8 @@ export default function page() {
// const poster = usePoster(playSettings, api);
// const user = useAtomValue(userAtom);
const router = useRouter();
const screenDimensions = Dimensions.get("screen");
const [isPlaybackStopped, setIsPlaybackStopped] = useState(false);
@@ -46,8 +55,11 @@ export default function page() {
const isSeeking = useSharedValue(false);
const cacheProgress = useSharedValue(0);
if (!playSettings || !playUrl || !api || !playSettings.item || !mediaSource)
if (!playSettings || !playUrl || !api || !playSettings.item || !mediaSource) {
Alert.alert("Error", "Invalid play settings");
router.back();
return null;
}
const togglePlay = useCallback(
async (ticks: number) => {
@@ -136,6 +148,7 @@ export default function page() {
const { currentTime, isPlaying } = data.nativeEvent;
progress.value = currentTime;
const currentTimeInTicks = msToTicks(currentTime);
await getPlaystateApi(api).onPlaybackProgress({
@@ -198,6 +211,13 @@ export default function page() {
}
};
useEffect(() => {
console.log(
"PlaybackPositionTicks",
playSettings.item?.UserData?.PlaybackPositionTicks
);
}, [playSettings.item]);
return (
<View
style={{
@@ -232,6 +252,14 @@ export default function page() {
onVideoLoadEnd={() => {
setIsVideoLoaded(true);
}}
onVideoError={(e) => {
console.error("Video Error:", e.nativeEvent);
Alert.alert(
"Error",
"An error occurred while playing the video. Check logs in settings."
);
writeToLog("ERROR", "Video Error", e.nativeEvent);
}}
/>
</Pressable>

View File

@@ -33,7 +33,8 @@ public class VlcPlayerModule: Module {
"onVideoStateChange",
"onVideoLoadStart",
"onVideoLoadEnd",
"onVideoProgress"
"onVideoProgress",
"onVideoError"
)
AsyncFunction("play") { (view: VlcPlayerView) in

View File

@@ -99,7 +99,13 @@ class VlcPlayerView: ExpoView {
let isNetwork = source["isNetwork"] as? Bool ?? false
let startPosition = source["startPosition"] as? Int32 ?? 0
guard let uri = uri, !uri.isEmpty else { return }
guard let uri = uri, !uri.isEmpty else {
print("Error: Invalid or empty URI")
self.onVideoError?(["error": "Invalid or empty URI"])
return
}
self.onVideoLoadStart?(["target": self.reactTag ?? NSNull()])
if initType == 2, let options = initOptions {
self.mediaPlayer = VLCMediaPlayer(options: options)
@@ -128,6 +134,7 @@ class VlcPlayerView: ExpoView {
media = VLCMedia(path: uri)
}
}
// Apply subtitle options
let subtitleOptions = self.getSubtitleOptions()
media.addOptions(subtitleOptions)
@@ -141,6 +148,7 @@ class VlcPlayerView: ExpoView {
print("Debug: No additional media options provided")
}
// Apply subtitle options
let subtitleTrackIndex = source["subtitleTrackIndex"] as? Int ?? -1
print("Debug: Subtitle track index from source: \(subtitleTrackIndex)")
@@ -154,14 +162,25 @@ class VlcPlayerView: ExpoView {
self.mediaPlayer?.media = media
if startPosition > 0 {
self.mediaPlayer?.time = VLCTime(int: startPosition)
// Wait for the media to be ready before setting the start position
NotificationCenter.default.addObserver(
forName: NSNotification.Name(rawValue: VLCMediaPlayerStateChanged), object: nil,
queue: nil
) { [weak self] notification in
guard let self = self, let player = self.mediaPlayer,
player.isPlaying == false
else { return }
self.mediaPlayer?.time = VLCTime(int: startPosition)
NotificationCenter.default.removeObserver(
self, name: NSNotification.Name(rawValue: VLCMediaPlayerStateChanged),
object: nil)
}
}
if autoplay {
self.play()
}
self.onVideoLoadStart?(["target": self.reactTag ?? NSNull()])
}
}
@@ -520,6 +539,7 @@ class VlcPlayerView: ExpoView {
@objc var onVideoStateChange: RCTDirectEventBlock?
@objc var onVideoProgress: RCTDirectEventBlock?
@objc var onVideoLoadEnd: RCTDirectEventBlock?
@objc var onVideoError: RCTDirectEventBlock?
// MARK: - Deinitialization
@@ -545,6 +565,7 @@ extension VlcPlayerView: VLCMediaPlayerDelegate {
"target": self.reactTag ?? NSNull(),
"currentTime": player.time.intValue,
"duration": player.media?.length.intValue ?? 0,
"error": false,
]
if player.isPlaying {
@@ -556,9 +577,16 @@ extension VlcPlayerView: VLCMediaPlayerDelegate {
stateInfo["state"] = "Paused"
}
if player.state == .buffering {
if player.state == VLCMediaPlayerState.buffering {
stateInfo["isBuffering"] = true
stateInfo["state"] = "Buffering"
} else if player.state == VLCMediaPlayerState.error {
print("player.state ~ error")
stateInfo["state"] = "Error"
self.onVideoLoadEnd?(stateInfo)
} else if player.state == VLCMediaPlayerState.opening {
print("player.state ~ opening")
stateInfo["state"] = "Opening"
}
// Dermine if the media has finished loading

View File

@@ -1,15 +1,7 @@
export type PlaybackStatePayload = {
nativeEvent: {
target: number;
state:
| "Opening"
| "Buffering"
| "Playing"
| "Paused"
| "Stopped"
| "Ended"
| "Error"
| "Unknown";
state: "Opening" | "Buffering" | "Playing" | "Paused" | "Error";
currentTime: number;
duration: number;
isBuffering: boolean;
@@ -69,6 +61,7 @@ export type VlcPlayerViewProps = {
onVideoStateChange?: (event: PlaybackStatePayload) => void;
onVideoLoadStart?: (event: VideoLoadStartPayload) => void;
onVideoLoadEnd?: (event: VideoLoadStartPayload) => void;
onVideoError?: (event: PlaybackStatePayload) => void;
};
export interface VlcPlayerViewRef {

View File

@@ -95,6 +95,7 @@ const VlcPlayerView = React.forwardRef<VlcPlayerViewRef, VlcPlayerViewProps>(
onVideoStateChange,
onVideoProgress,
onVideoLoadEnd,
onVideoError,
...otherProps
} = props;
@@ -120,6 +121,7 @@ const VlcPlayerView = React.forwardRef<VlcPlayerViewRef, VlcPlayerViewProps>(
onVideoLoadEnd={onVideoLoadEnd}
onVideoStateChange={onVideoStateChange}
onVideoProgress={onVideoProgress}
onVideoError={onVideoError}
/>
);
}