@zezosoft/zezo-ott-react-native-video-player 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -26
- package/lib/module/AdsPlayer/AdsPlayer.js +7 -11
- package/lib/module/AdsPlayer/AdsPlayer.js.map +1 -1
- package/lib/module/AdsPlayer/MediaControls/AdBottomControls.js +3 -1
- package/lib/module/AdsPlayer/MediaControls/AdBottomControls.js.map +1 -1
- package/lib/module/AdsPlayer/MediaControls/AdMediaControls.js +12 -7
- package/lib/module/AdsPlayer/MediaControls/AdMediaControls.js.map +1 -1
- package/lib/module/AdsPlayer/MediaControls/AdTopControls.js +5 -17
- package/lib/module/AdsPlayer/MediaControls/AdTopControls.js.map +1 -1
- package/lib/module/VideoPlayer/MediaControls/BottomControls.js +15 -7
- package/lib/module/VideoPlayer/MediaControls/BottomControls.js.map +1 -1
- package/lib/module/VideoPlayer/MediaControls/MediaControls.js +4 -5
- package/lib/module/VideoPlayer/MediaControls/MediaControls.js.map +1 -1
- package/lib/module/VideoPlayer/MediaControls/MediaControlsProvider.js +8 -5
- package/lib/module/VideoPlayer/MediaControls/MediaControlsProvider.js.map +1 -1
- package/lib/module/VideoPlayer/MediaControls/TopControls.js +4 -11
- package/lib/module/VideoPlayer/MediaControls/TopControls.js.map +1 -1
- package/lib/module/VideoPlayer/components/ProgressBar.js +39 -4
- package/lib/module/VideoPlayer/components/ProgressBar.js.map +1 -1
- package/lib/module/VideoPlayer/utils/hooks/useVideoResolutions.js +11 -7
- package/lib/module/VideoPlayer/utils/hooks/useVideoResolutions.js.map +1 -1
- package/lib/module/VideoPlayer.js +26 -14
- package/lib/module/VideoPlayer.js.map +1 -1
- package/lib/typescript/src/AdsPlayer/AdsPlayer.d.ts.map +1 -1
- package/lib/typescript/src/AdsPlayer/MediaControls/AdBottomControls.d.ts.map +1 -1
- package/lib/typescript/src/AdsPlayer/MediaControls/AdMediaControls.d.ts.map +1 -1
- package/lib/typescript/src/AdsPlayer/MediaControls/AdTopControls.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/MediaControls/MediaControls.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/MediaControls/MediaControlsProvider.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/MediaControls/TopControls.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/components/ProgressBar.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/utils/hooks/useVideoResolutions.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/AdsPlayer/AdsPlayer.tsx +12 -13
- package/src/AdsPlayer/MediaControls/AdBottomControls.tsx +3 -1
- package/src/AdsPlayer/MediaControls/AdMediaControls.tsx +13 -7
- package/src/AdsPlayer/MediaControls/AdTopControls.tsx +8 -13
- package/src/VideoPlayer/MediaControls/BottomControls.tsx +13 -7
- package/src/VideoPlayer/MediaControls/MediaControls.tsx +4 -4
- package/src/VideoPlayer/MediaControls/MediaControlsProvider.tsx +9 -5
- package/src/VideoPlayer/MediaControls/TopControls.tsx +4 -10
- package/src/VideoPlayer/components/ProgressBar.tsx +53 -4
- package/src/VideoPlayer/utils/hooks/useVideoResolutions.ts +17 -9
- package/src/VideoPlayer.tsx +44 -29
|
@@ -23,8 +23,14 @@ const AdTopControls: React.FC<AdTopControlsProps> = ({ onClose }) => {
|
|
|
23
23
|
const controlsVisible = useVideoPlayerStore((state) => state.controlsVisible);
|
|
24
24
|
const currentAd = useAdsPlayerStore((state) => state.currentAd);
|
|
25
25
|
const adCurrentTime = useAdsPlayerStore((state) => state.adCurrentTime);
|
|
26
|
+
const adDuration = useAdsPlayerStore((state) => state.adDuration);
|
|
26
27
|
const fadeAnim = useAdControlsAutoHide();
|
|
27
28
|
|
|
29
|
+
const adTimeRemaining = useMemo(
|
|
30
|
+
() => Math.max(0, (currentAd?.duration ?? adDuration) - adCurrentTime),
|
|
31
|
+
[currentAd?.duration, adDuration, adCurrentTime]
|
|
32
|
+
);
|
|
33
|
+
|
|
28
34
|
// Memoize styles to avoid recalculation
|
|
29
35
|
const adLabelContainerStyle = useMemo(
|
|
30
36
|
() => [
|
|
@@ -58,7 +64,7 @@ const AdTopControls: React.FC<AdTopControlsProps> = ({ onClose }) => {
|
|
|
58
64
|
<Text style={styles.adLabelText}>Ad</Text>
|
|
59
65
|
</View>
|
|
60
66
|
<View style={styles.separator} />
|
|
61
|
-
<Text style={styles.adTimeText}>{formatTime(
|
|
67
|
+
<Text style={styles.adTimeText}>{formatTime(adTimeRemaining)}</Text>
|
|
62
68
|
</View>
|
|
63
69
|
</Animated.View>
|
|
64
70
|
)}
|
|
@@ -81,7 +87,7 @@ const styles = StyleSheet.create({
|
|
|
81
87
|
container: {
|
|
82
88
|
flexDirection: 'row',
|
|
83
89
|
justifyContent: 'space-between',
|
|
84
|
-
alignItems: '
|
|
90
|
+
alignItems: 'center',
|
|
85
91
|
marginTop: moderateScale(8),
|
|
86
92
|
paddingHorizontal: moderateScale(10),
|
|
87
93
|
paddingBottom: 0,
|
|
@@ -179,17 +185,6 @@ const styles = StyleSheet.create({
|
|
|
179
185
|
alignItems: 'center',
|
|
180
186
|
borderWidth: 1,
|
|
181
187
|
borderColor: 'rgba(255, 255, 255, 0.2)',
|
|
182
|
-
...Platform.select({
|
|
183
|
-
ios: {
|
|
184
|
-
shadowColor: '#000',
|
|
185
|
-
shadowOffset: { width: 0, height: 2 },
|
|
186
|
-
shadowOpacity: 0.25,
|
|
187
|
-
shadowRadius: 3,
|
|
188
|
-
},
|
|
189
|
-
android: {
|
|
190
|
-
elevation: 3,
|
|
191
|
-
},
|
|
192
|
-
}),
|
|
193
188
|
},
|
|
194
189
|
});
|
|
195
190
|
|
|
@@ -109,7 +109,7 @@ const BottomControls = () => {
|
|
|
109
109
|
);
|
|
110
110
|
|
|
111
111
|
return (
|
|
112
|
-
<View>
|
|
112
|
+
<View style={styles.root}>
|
|
113
113
|
{/* Progress Bar Section */}
|
|
114
114
|
<View style={styles.sliderContainer}>
|
|
115
115
|
<View style={styles.sliderWrapper}>
|
|
@@ -121,7 +121,7 @@ const BottomControls = () => {
|
|
|
121
121
|
adMarkers={adMarkers}
|
|
122
122
|
/>
|
|
123
123
|
</View>
|
|
124
|
-
<Text style={timeTextStyle}>
|
|
124
|
+
<Text style={timeTextStyle} numberOfLines={1}>
|
|
125
125
|
{getRemainingTime(duration, currentTime)}
|
|
126
126
|
</Text>
|
|
127
127
|
</View>
|
|
@@ -166,35 +166,41 @@ const BottomControls = () => {
|
|
|
166
166
|
export default BottomControls;
|
|
167
167
|
|
|
168
168
|
const styles = StyleSheet.create({
|
|
169
|
+
root: {
|
|
170
|
+
paddingTop: verticalScale(8),
|
|
171
|
+
paddingBottom: verticalScale(4),
|
|
172
|
+
},
|
|
169
173
|
sliderContainer: {
|
|
170
174
|
flexDirection: 'row',
|
|
171
175
|
alignItems: 'center',
|
|
172
176
|
paddingHorizontal: scale(12),
|
|
177
|
+
marginBottom: verticalScale(4),
|
|
173
178
|
},
|
|
174
179
|
sliderWrapper: {
|
|
175
180
|
flex: 1,
|
|
176
181
|
minWidth: 0,
|
|
177
182
|
},
|
|
178
183
|
timeText: {
|
|
179
|
-
|
|
184
|
+
minWidth: scale(52),
|
|
185
|
+
maxWidth: scale(56),
|
|
180
186
|
textAlign: 'right',
|
|
181
|
-
marginLeft: scale(
|
|
187
|
+
marginLeft: scale(6),
|
|
182
188
|
fontSize: RFValue(12),
|
|
183
189
|
fontWeight: '500',
|
|
184
190
|
},
|
|
185
191
|
buttonsContainer: {
|
|
186
192
|
flexDirection: 'row',
|
|
187
|
-
justifyContent: 'center',
|
|
188
193
|
flexWrap: 'wrap',
|
|
194
|
+
justifyContent: 'center',
|
|
195
|
+
alignContent: 'center',
|
|
189
196
|
paddingHorizontal: scale(10),
|
|
197
|
+
gap: scale(4),
|
|
190
198
|
},
|
|
191
199
|
button: {
|
|
192
200
|
flexDirection: 'row',
|
|
193
201
|
alignItems: 'center',
|
|
194
202
|
paddingHorizontal: scale(12),
|
|
195
203
|
paddingVertical: verticalScale(6),
|
|
196
|
-
marginHorizontal: scale(6),
|
|
197
|
-
marginVertical: verticalScale(4),
|
|
198
204
|
borderRadius: moderateScale(8),
|
|
199
205
|
},
|
|
200
206
|
buttonText: {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { memo } from 'react';
|
|
2
|
-
import { StyleSheet } from 'react-native';
|
|
3
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
2
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
3
|
import TopControls from './TopControls';
|
|
5
4
|
import MiddleControls from './MiddleControls';
|
|
6
5
|
import BottomControls from './BottomControls';
|
|
@@ -11,11 +10,11 @@ export type MediaControlsProps = {
|
|
|
11
10
|
|
|
12
11
|
const MediaControls: React.FC<MediaControlsProps> = ({ onClose }) => {
|
|
13
12
|
return (
|
|
14
|
-
<
|
|
13
|
+
<View style={styles.container}>
|
|
15
14
|
<TopControls onClose={onClose} />
|
|
16
15
|
<MiddleControls />
|
|
17
16
|
<BottomControls />
|
|
18
|
-
</
|
|
17
|
+
</View>
|
|
19
18
|
);
|
|
20
19
|
};
|
|
21
20
|
|
|
@@ -26,5 +25,6 @@ const styles = StyleSheet.create({
|
|
|
26
25
|
flex: 1,
|
|
27
26
|
flexDirection: 'column',
|
|
28
27
|
justifyContent: 'space-between',
|
|
28
|
+
minHeight: 0,
|
|
29
29
|
},
|
|
30
30
|
});
|
|
@@ -11,6 +11,10 @@ import globalStyles from '../styles/globalStyles';
|
|
|
11
11
|
import type { ExtendedWatchProgress } from '../utils';
|
|
12
12
|
import SubtitleView from '../components/SubtitleView';
|
|
13
13
|
|
|
14
|
+
const HORIZONTAL_PADDING = moderateScale(12);
|
|
15
|
+
const BOTTOM_PADDING_EXTRA = moderateScale(8);
|
|
16
|
+
const MIN_TOP_PADDING = moderateScale(10);
|
|
17
|
+
|
|
14
18
|
interface MediaControlsProviderProps extends MediaControlsProps {
|
|
15
19
|
children: React.ReactNode;
|
|
16
20
|
onPressEpisode: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
|
|
@@ -34,13 +38,13 @@ const MediaControlsProvider: React.FC<MediaControlsProviderProps> = ({
|
|
|
34
38
|
const timeoutId = React.useRef<NodeJS.Timeout | null>(null);
|
|
35
39
|
const fadeAnim = useRef(new Animated.Value(0)).current;
|
|
36
40
|
|
|
37
|
-
//
|
|
41
|
+
// Safe-area padding: never negative, single source of truth (MediaControls uses View, not SafeAreaView)
|
|
38
42
|
const containerPadding: ViewStyle = useMemo(
|
|
39
43
|
() => ({
|
|
40
|
-
paddingTop: top,
|
|
41
|
-
paddingBottom: bottom +
|
|
42
|
-
paddingLeft: left +
|
|
43
|
-
paddingRight: right +
|
|
44
|
+
paddingTop: top - MIN_TOP_PADDING,
|
|
45
|
+
paddingBottom: bottom + BOTTOM_PADDING_EXTRA,
|
|
46
|
+
paddingLeft: left + HORIZONTAL_PADDING,
|
|
47
|
+
paddingRight: right + HORIZONTAL_PADDING,
|
|
44
48
|
}),
|
|
45
49
|
[top, bottom, left, right]
|
|
46
50
|
);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { moderateScale } from 'react-native-size-matters';
|
|
4
4
|
import { RFValue } from 'react-native-responsive-fontsize';
|
|
5
5
|
import { X } from 'lucide-react-native';
|
|
6
6
|
import { lockToPortrait } from '../utils';
|
|
7
|
-
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
8
7
|
import { useVideoPlayerConfig } from '../context';
|
|
9
8
|
import { useVideoPlayerStore } from '../store/videoPlayerStore';
|
|
10
9
|
|
|
@@ -14,7 +13,6 @@ interface TopControlsProps {
|
|
|
14
13
|
|
|
15
14
|
const TopControls: React.FC<TopControlsProps> = ({ onClose }) => {
|
|
16
15
|
const { activeTrack } = useVideoPlayerStore();
|
|
17
|
-
const { top } = useSafeAreaInsets();
|
|
18
16
|
const { colors } = useVideoPlayerConfig();
|
|
19
17
|
const handleClose = () => {
|
|
20
18
|
// onClose already handles reportProgress and store reset in VideoPlayerCore
|
|
@@ -27,14 +25,8 @@ const TopControls: React.FC<TopControlsProps> = ({ onClose }) => {
|
|
|
27
25
|
activeTrack?.seasonNumber !== undefined ||
|
|
28
26
|
activeTrack?.episodeNumber !== undefined;
|
|
29
27
|
|
|
30
|
-
// Memoize container style to avoid recalculation
|
|
31
|
-
const containerStyle = useMemo(
|
|
32
|
-
() => [styles.container, { paddingTop: top + moderateScale(10) }],
|
|
33
|
-
[top]
|
|
34
|
-
);
|
|
35
|
-
|
|
36
28
|
return (
|
|
37
|
-
<View style={
|
|
29
|
+
<View style={styles.container}>
|
|
38
30
|
<View style={styles.textContainer}>
|
|
39
31
|
<Text
|
|
40
32
|
numberOfLines={1}
|
|
@@ -81,10 +73,12 @@ const styles = StyleSheet.create({
|
|
|
81
73
|
justifyContent: 'space-between',
|
|
82
74
|
alignItems: 'center',
|
|
83
75
|
paddingHorizontal: moderateScale(16),
|
|
76
|
+
paddingVertical: moderateScale(8),
|
|
84
77
|
zIndex: 51,
|
|
85
78
|
},
|
|
86
79
|
textContainer: {
|
|
87
80
|
flex: 1,
|
|
81
|
+
minWidth: 0,
|
|
88
82
|
paddingRight: moderateScale(10),
|
|
89
83
|
},
|
|
90
84
|
title: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
-
import React, { useEffect, useMemo, useCallback } from 'react';
|
|
2
|
+
import React, { useEffect, useMemo, useCallback, useRef } from 'react';
|
|
3
3
|
import { View, StyleSheet } from 'react-native';
|
|
4
4
|
import { Slider } from 'react-native-awesome-slider';
|
|
5
|
-
import { useSharedValue, withTiming } from 'react-native-reanimated';
|
|
5
|
+
import { useSharedValue, withTiming, Easing } from 'react-native-reanimated';
|
|
6
6
|
import { moderateScale } from 'react-native-size-matters';
|
|
7
7
|
import { useVideoPlayerConfig } from '../context';
|
|
8
8
|
|
|
@@ -17,6 +17,11 @@ interface Props {
|
|
|
17
17
|
adMarkers?: number[];
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
const SEEK_COOLDOWN_MS = 400;
|
|
21
|
+
const PROGRESS_ANIM_DURATION = 220;
|
|
22
|
+
const CACHE_ANIM_DURATION = 280;
|
|
23
|
+
const SMOOTH_EASING = Easing.bezier(0.25, 0.1, 0.25, 1);
|
|
24
|
+
|
|
20
25
|
const ProgressBar: React.FC<Props> = React.memo(
|
|
21
26
|
({
|
|
22
27
|
duration,
|
|
@@ -39,12 +44,26 @@ const ProgressBar: React.FC<Props> = React.memo(
|
|
|
39
44
|
const min = useSharedValue(0);
|
|
40
45
|
const max = useSharedValue(duration);
|
|
41
46
|
|
|
47
|
+
const isSlidingRef = useRef(false);
|
|
48
|
+
const seekCooldownUntilRef = useRef(0);
|
|
49
|
+
const seekCooldownTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
|
|
50
|
+
null
|
|
51
|
+
);
|
|
52
|
+
|
|
42
53
|
useEffect(() => {
|
|
43
|
-
|
|
54
|
+
if (isSlidingRef.current) return;
|
|
55
|
+
if (Date.now() < seekCooldownUntilRef.current) return;
|
|
56
|
+
progress.value = withTiming(currentTime, {
|
|
57
|
+
duration: PROGRESS_ANIM_DURATION,
|
|
58
|
+
easing: SMOOTH_EASING,
|
|
59
|
+
});
|
|
44
60
|
}, [currentTime]);
|
|
45
61
|
|
|
46
62
|
useEffect(() => {
|
|
47
|
-
cache.value = withTiming(bufferedTime, {
|
|
63
|
+
cache.value = withTiming(bufferedTime, {
|
|
64
|
+
duration: CACHE_ANIM_DURATION,
|
|
65
|
+
easing: SMOOTH_EASING,
|
|
66
|
+
});
|
|
48
67
|
}, [bufferedTime]);
|
|
49
68
|
|
|
50
69
|
useEffect(() => {
|
|
@@ -63,6 +82,34 @@ const ProgressBar: React.FC<Props> = React.memo(
|
|
|
63
82
|
[onSeek, disabled]
|
|
64
83
|
);
|
|
65
84
|
|
|
85
|
+
const handleSlidingStart = useCallback(() => {
|
|
86
|
+
isSlidingRef.current = true;
|
|
87
|
+
if (seekCooldownTimeoutRef.current) {
|
|
88
|
+
clearTimeout(seekCooldownTimeoutRef.current);
|
|
89
|
+
seekCooldownTimeoutRef.current = null;
|
|
90
|
+
}
|
|
91
|
+
}, []);
|
|
92
|
+
|
|
93
|
+
const handleSlidingComplete = useCallback(
|
|
94
|
+
(value: number) => {
|
|
95
|
+
progress.value = value;
|
|
96
|
+
seekCooldownUntilRef.current = Date.now() + SEEK_COOLDOWN_MS;
|
|
97
|
+
seekCooldownTimeoutRef.current = setTimeout(() => {
|
|
98
|
+
isSlidingRef.current = false;
|
|
99
|
+
seekCooldownTimeoutRef.current = null;
|
|
100
|
+
}, SEEK_COOLDOWN_MS);
|
|
101
|
+
},
|
|
102
|
+
[progress]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
return () => {
|
|
107
|
+
if (seekCooldownTimeoutRef.current) {
|
|
108
|
+
clearTimeout(seekCooldownTimeoutRef.current);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
66
113
|
return (
|
|
67
114
|
<View style={[styles.container, { height: thumbSize }]}>
|
|
68
115
|
<Slider
|
|
@@ -71,6 +118,8 @@ const ProgressBar: React.FC<Props> = React.memo(
|
|
|
71
118
|
maximumValue={max}
|
|
72
119
|
cache={cache}
|
|
73
120
|
disable={disabled}
|
|
121
|
+
onSlidingStart={handleSlidingStart}
|
|
122
|
+
onSlidingComplete={handleSlidingComplete}
|
|
74
123
|
onValueChange={handleSeek}
|
|
75
124
|
containerStyle={[
|
|
76
125
|
styles.sliderContainer,
|
|
@@ -9,12 +9,15 @@ export interface StreamInfo {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
async function getHLSBandwidthAndResolutions(
|
|
12
|
-
m3u8Url: string
|
|
12
|
+
m3u8Url: string,
|
|
13
|
+
headers?: Record<string, string>
|
|
13
14
|
): Promise<StreamInfo[]> {
|
|
14
15
|
try {
|
|
15
16
|
if (!m3u8Url?.endsWith('.m3u8')) return [];
|
|
16
17
|
|
|
17
|
-
const { data } = await axios.get<string>(m3u8Url
|
|
18
|
+
const { data } = await axios.get<string>(m3u8Url, {
|
|
19
|
+
headers: headers ?? undefined,
|
|
20
|
+
});
|
|
18
21
|
if (!data) return [];
|
|
19
22
|
|
|
20
23
|
const lines = data.split('\n');
|
|
@@ -58,8 +61,7 @@ async function getHLSBandwidthAndResolutions(
|
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
return [autoStream, ...streams];
|
|
61
|
-
} catch
|
|
62
|
-
console.error('Error fetching or parsing HLS stream:', error);
|
|
64
|
+
} catch {
|
|
63
65
|
return [];
|
|
64
66
|
}
|
|
65
67
|
}
|
|
@@ -87,30 +89,36 @@ export const useVideoResolutions = (track: MediaTrack | null) => {
|
|
|
87
89
|
return;
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
let cancelled = false;
|
|
93
|
+
|
|
90
94
|
const fetchResolutions = async () => {
|
|
91
95
|
try {
|
|
92
96
|
const data = await getHLSBandwidthAndResolutions(source);
|
|
97
|
+
if (cancelled) return;
|
|
93
98
|
|
|
94
99
|
const filteredData = data.filter(
|
|
95
|
-
(item)
|
|
100
|
+
(item): item is StreamInfo & { height: number } =>
|
|
101
|
+
typeof item.height === 'number'
|
|
96
102
|
);
|
|
97
103
|
|
|
98
104
|
const newResolutions: Resolution[] = [
|
|
99
105
|
{ height: 'auto', bandwidth: null },
|
|
100
106
|
...filteredData.map((item) => ({
|
|
101
|
-
height: item.height
|
|
107
|
+
height: item.height,
|
|
102
108
|
bandwidth: item.bandwidth,
|
|
103
109
|
})),
|
|
104
110
|
];
|
|
105
111
|
|
|
106
112
|
resolutionCache[source] = newResolutions;
|
|
107
113
|
setResolutions(newResolutions);
|
|
108
|
-
} catch
|
|
109
|
-
console.error('Failed to fetch video resolutions', error);
|
|
110
|
-
}
|
|
114
|
+
} catch {}
|
|
111
115
|
};
|
|
112
116
|
|
|
113
117
|
fetchResolutions();
|
|
118
|
+
|
|
119
|
+
return () => {
|
|
120
|
+
cancelled = true;
|
|
121
|
+
};
|
|
114
122
|
}, [track]);
|
|
115
123
|
|
|
116
124
|
return resolutions;
|
package/src/VideoPlayer.tsx
CHANGED
|
@@ -118,37 +118,45 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|
|
118
118
|
onClose?.();
|
|
119
119
|
}, [onClose]);
|
|
120
120
|
|
|
121
|
+
const showAdsOverlay =
|
|
122
|
+
ads.length > 0 && isAdPlaying && currentAd && !activeTrack?.isTrailer;
|
|
123
|
+
|
|
121
124
|
return (
|
|
122
125
|
<View style={styles.container}>
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
126
|
+
<View
|
|
127
|
+
style={[
|
|
128
|
+
styles.mainPlayerWrapper,
|
|
129
|
+
showAdsOverlay && styles.mainPlayerHidden,
|
|
130
|
+
]}
|
|
131
|
+
pointerEvents={showAdsOverlay ? 'none' : 'auto'}
|
|
132
|
+
>
|
|
133
|
+
<VideoPlayerCore
|
|
134
|
+
onClose={onClose}
|
|
135
|
+
isFocused={isFocused}
|
|
136
|
+
mode={mode}
|
|
137
|
+
seekTime={seekTime}
|
|
138
|
+
event={event}
|
|
139
|
+
autoNext={autoNext}
|
|
140
|
+
theme={theme}
|
|
141
|
+
onWatchProgress={onWatchProgress}
|
|
142
|
+
insets={insets}
|
|
143
|
+
isPausedOverride={isAdPlaying ? true : isPaused}
|
|
144
|
+
onVideoEnd={handleVideoEnd}
|
|
145
|
+
/>
|
|
146
|
+
</View>
|
|
147
|
+
{showAdsOverlay && (
|
|
148
|
+
<View style={styles.adsOverlay}>
|
|
149
|
+
<AdsPlayer
|
|
150
|
+
ref={adVideoRef}
|
|
151
|
+
insets={insets}
|
|
152
|
+
onAdEnd={handleAdEnd}
|
|
153
|
+
onAdSkip={handleAdSkip}
|
|
154
|
+
onAdError={handleAdError}
|
|
155
|
+
onAdTracking={onAdTracking}
|
|
156
|
+
onClose={handleAdClose}
|
|
157
|
+
/>
|
|
158
|
+
</View>
|
|
159
|
+
)}
|
|
152
160
|
</View>
|
|
153
161
|
);
|
|
154
162
|
};
|
|
@@ -157,9 +165,16 @@ const styles = StyleSheet.create({
|
|
|
157
165
|
container: {
|
|
158
166
|
flex: 1,
|
|
159
167
|
},
|
|
168
|
+
mainPlayerWrapper: {
|
|
169
|
+
flex: 1,
|
|
170
|
+
},
|
|
171
|
+
mainPlayerHidden: {
|
|
172
|
+
opacity: 0,
|
|
173
|
+
},
|
|
160
174
|
adsOverlay: {
|
|
161
175
|
...StyleSheet.absoluteFillObject,
|
|
162
176
|
zIndex: 1000,
|
|
177
|
+
backgroundColor: 'black',
|
|
163
178
|
},
|
|
164
179
|
});
|
|
165
180
|
|