mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
playback control optimization
This commit is contained in:
parent
6fa53151fb
commit
33d13c74d3
4 changed files with 65 additions and 15 deletions
|
|
@ -786,15 +786,37 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
}
|
||||
}, [isSpeedBoosted, playbackSpeed, holdToSpeedEnabled, holdToSpeedValue, speedActivatedOverlayOpacity]);
|
||||
|
||||
const onLongPressEnd = useCallback(() => {
|
||||
const restoreSpeedSafely = useCallback(() => {
|
||||
if (isSpeedBoosted) {
|
||||
setPlaybackSpeed(originalSpeed);
|
||||
setIsSpeedBoosted(false);
|
||||
|
||||
logger.log('[AndroidVideoPlayer] Speed boost deactivated, restored to:', originalSpeed);
|
||||
}
|
||||
}, [isSpeedBoosted, originalSpeed]);
|
||||
|
||||
const onLongPressEnd = useCallback(() => {
|
||||
restoreSpeedSafely();
|
||||
}, [restoreSpeedSafely]);
|
||||
|
||||
const onLongPressStateChange = useCallback((event: LongPressGestureHandlerGestureEvent) => {
|
||||
// Fallback: ensure we restore on cancel/fail transitions as well
|
||||
// @ts-ignore - event.nativeEvent.state uses numeric State enum
|
||||
const state = event?.nativeEvent?.state;
|
||||
if (state === State.CANCELLED || state === State.FAILED || state === State.END) {
|
||||
restoreSpeedSafely();
|
||||
}
|
||||
}, [restoreSpeedSafely]);
|
||||
|
||||
// Safety: if component unmounts while boosted, restore speed
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (isSpeedBoosted) {
|
||||
// best-effort restoration on unmount
|
||||
try { setPlaybackSpeed(originalSpeed); } catch {}
|
||||
}
|
||||
};
|
||||
}, [isSpeedBoosted, originalSpeed]);
|
||||
|
||||
const resetZoom = () => {
|
||||
const targetZoom = is16by9Content ? 1.1 : 1;
|
||||
setZoomScale(targetZoom);
|
||||
|
|
@ -3147,6 +3169,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
<LongPressGestureHandler
|
||||
onActivated={onLongPressActivated}
|
||||
onEnded={onLongPressEnd}
|
||||
onHandlerStateChange={onLongPressStateChange}
|
||||
minDurationMs={500}
|
||||
shouldCancelWhenOutside={false}
|
||||
simultaneousHandlers={[]}
|
||||
|
|
@ -3180,6 +3203,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
<LongPressGestureHandler
|
||||
onActivated={onLongPressActivated}
|
||||
onEnded={onLongPressEnd}
|
||||
onHandlerStateChange={onLongPressStateChange}
|
||||
minDurationMs={500}
|
||||
shouldCancelWhenOutside={false}
|
||||
simultaneousHandlers={[]}
|
||||
|
|
|
|||
|
|
@ -521,15 +521,36 @@ const KSPlayerCore: React.FC = () => {
|
|||
}
|
||||
}, [isSpeedBoosted, playbackSpeed, holdToSpeedEnabled, holdToSpeedValue, speedActivatedOverlayOpacity]);
|
||||
|
||||
const onLongPressEnd = useCallback(() => {
|
||||
const restoreSpeedSafely = useCallback(() => {
|
||||
if (isSpeedBoosted) {
|
||||
setPlaybackSpeed(originalSpeed);
|
||||
setIsSpeedBoosted(false);
|
||||
|
||||
logger.log('[KSPlayerCore] Speed boost deactivated, restored to:', originalSpeed);
|
||||
}
|
||||
}, [isSpeedBoosted, originalSpeed]);
|
||||
|
||||
const onLongPressEnd = useCallback(() => {
|
||||
restoreSpeedSafely();
|
||||
}, [restoreSpeedSafely]);
|
||||
|
||||
const onLongPressStateChange = useCallback((event: LongPressGestureHandlerGestureEvent) => {
|
||||
// Ensure restoration on cancel/fail/end as well
|
||||
// @ts-ignore - numeric State enum
|
||||
const state = event?.nativeEvent?.state;
|
||||
if (state === State.CANCELLED || state === State.FAILED || state === State.END) {
|
||||
restoreSpeedSafely();
|
||||
}
|
||||
}, [restoreSpeedSafely]);
|
||||
|
||||
// Safety: restore speed on unmount if still boosted
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (isSpeedBoosted) {
|
||||
try { setPlaybackSpeed(originalSpeed); } catch {}
|
||||
}
|
||||
};
|
||||
}, [isSpeedBoosted, originalSpeed]);
|
||||
|
||||
useEffect(() => {
|
||||
if (videoAspectRatio && effectiveDimensions.width > 0 && effectiveDimensions.height > 0) {
|
||||
const styles = calculateVideoStyles(
|
||||
|
|
@ -2535,6 +2556,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
<LongPressGestureHandler
|
||||
onActivated={onLongPressActivated}
|
||||
onEnded={onLongPressEnd}
|
||||
onHandlerStateChange={onLongPressStateChange}
|
||||
minDurationMs={500}
|
||||
shouldCancelWhenOutside={false}
|
||||
simultaneousHandlers={[]}
|
||||
|
|
@ -2568,6 +2590,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
<LongPressGestureHandler
|
||||
onActivated={onLongPressActivated}
|
||||
onEnded={onLongPressEnd}
|
||||
onHandlerStateChange={onLongPressStateChange}
|
||||
minDurationMs={500}
|
||||
shouldCancelWhenOutside={false}
|
||||
simultaneousHandlers={[]}
|
||||
|
|
|
|||
|
|
@ -871,7 +871,7 @@ export const StreamsScreen = () => {
|
|||
try {
|
||||
if (stream.url) {
|
||||
// Block magnet links - not supported yet
|
||||
if (stream.url.startsWith('magnet:')) {
|
||||
if (typeof stream.url === 'string' && stream.url.startsWith('magnet:')) {
|
||||
try {
|
||||
openAlert('Not supported', 'Torrent streaming is not supported yet.');
|
||||
} catch (_e) {}
|
||||
|
|
@ -1032,7 +1032,7 @@ export const StreamsScreen = () => {
|
|||
if (__DEV__) console.log('Opening stream with Android native app chooser');
|
||||
|
||||
// For Android, determine if the URL is a direct http/https URL or a magnet link
|
||||
const isMagnet = stream.url.startsWith('magnet:');
|
||||
const isMagnet = typeof stream.url === 'string' && stream.url.startsWith('magnet:');
|
||||
|
||||
if (isMagnet) {
|
||||
// For magnet links, open directly which will trigger the torrent app chooser
|
||||
|
|
@ -1884,7 +1884,7 @@ export const StreamsScreen = () => {
|
|||
</View>
|
||||
)}
|
||||
|
||||
{metadata?.videos && metadata.videos.length > 1 && selectedEpisode && (
|
||||
{currentEpisode && (
|
||||
<View style={[
|
||||
styles.streamsHeroContainer,
|
||||
!settings.enableStreamsBackdrop && { backgroundColor: colors.darkBackground }
|
||||
|
|
|
|||
|
|
@ -1382,17 +1382,20 @@ class StremioService {
|
|||
}
|
||||
|
||||
private isDirectStreamingUrl(url?: string): boolean {
|
||||
return Boolean(
|
||||
url && (
|
||||
url.startsWith('http') ||
|
||||
url.startsWith('https')
|
||||
)
|
||||
);
|
||||
if (typeof url !== 'string') return false;
|
||||
return url.startsWith('http://') || url.startsWith('https://');
|
||||
}
|
||||
|
||||
private getStreamUrl(stream: any): string {
|
||||
if (stream.url) return stream.url;
|
||||
|
||||
// Prefer plain string URLs; guard against objects or unexpected types
|
||||
if (typeof stream?.url === 'string') {
|
||||
return stream.url;
|
||||
}
|
||||
// Some addons might nest the URL inside an object; try common shape
|
||||
if (stream?.url && typeof stream.url === 'object' && typeof stream.url.url === 'string') {
|
||||
return stream.url.url;
|
||||
}
|
||||
|
||||
if (stream.infoHash) {
|
||||
const trackers = [
|
||||
'udp://tracker.opentrackr.org:1337/announce',
|
||||
|
|
|
|||
Loading…
Reference in a new issue