playback control optimization

This commit is contained in:
tapframe 2025-10-30 18:33:57 +05:30
parent 6fa53151fb
commit 33d13c74d3
4 changed files with 65 additions and 15 deletions

View file

@ -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={[]}

View file

@ -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={[]}

View file

@ -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 }

View file

@ -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',