2015-12-06 22:25:18 -08:00
|
|
|
'use strict';
|
|
|
|
|
2024-09-04 09:53:30 +02:00
|
|
|
import React, {type FC, useCallback, useRef, useState, useEffect} from 'react';
|
2016-04-22 00:01:44 -04:00
|
|
|
|
2024-09-04 09:53:30 +02:00
|
|
|
import {Platform, TouchableOpacity, View, StatusBar} from 'react-native';
|
2016-02-10 11:39:54 +00:00
|
|
|
|
2023-10-26 08:46:04 +02:00
|
|
|
import Video, {
|
|
|
|
VideoRef,
|
2024-05-22 14:01:55 +02:00
|
|
|
SelectedVideoTrackType,
|
2024-05-11 22:02:04 +02:00
|
|
|
BufferingStrategyType,
|
2024-06-28 13:03:10 +03:30
|
|
|
SelectedTrackType,
|
2024-07-08 11:24:32 +03:30
|
|
|
ResizeMode,
|
2024-07-15 23:29:23 +02:00
|
|
|
type AudioTrack,
|
|
|
|
type OnAudioTracksData,
|
|
|
|
type OnLoadData,
|
|
|
|
type OnProgressData,
|
|
|
|
type OnTextTracksData,
|
|
|
|
type OnVideoAspectRatioData,
|
|
|
|
type TextTrack,
|
|
|
|
type OnBufferData,
|
|
|
|
type OnAudioFocusChangedData,
|
|
|
|
type OnVideoErrorData,
|
|
|
|
type OnTextTrackDataChangedData,
|
|
|
|
type OnSeekData,
|
|
|
|
type OnPlaybackStateChangedData,
|
|
|
|
type OnPlaybackRateChangeData,
|
|
|
|
type OnVideoTracksData,
|
|
|
|
type ReactVideoSource,
|
|
|
|
type VideoTrack,
|
|
|
|
type SelectedTrack,
|
|
|
|
type SelectedVideoTrack,
|
|
|
|
type EnumValues,
|
2024-09-03 15:33:43 +02:00
|
|
|
OnBandwidthUpdateData,
|
2023-10-26 08:46:04 +02:00
|
|
|
} from 'react-native-video';
|
2024-05-22 14:01:55 +02:00
|
|
|
import styles from './styles';
|
2024-07-15 23:29:23 +02:00
|
|
|
import {type AdditionalSourceInfo} from './types';
|
2024-09-14 19:53:54 +02:00
|
|
|
import {
|
|
|
|
bufferConfig,
|
|
|
|
isAndroid,
|
|
|
|
srcList,
|
|
|
|
textTracksSelectionBy,
|
2024-09-20 16:26:20 +02:00
|
|
|
audioTracksSelectionBy,
|
2024-09-14 19:53:54 +02:00
|
|
|
} from './constants';
|
2024-07-22 22:38:35 +02:00
|
|
|
import {Overlay, toast, VideoLoader} from './components';
|
2024-09-04 09:53:30 +02:00
|
|
|
import * as NavigationBar from 'expo-navigation-bar';
|
2024-06-28 13:03:10 +03:30
|
|
|
|
|
|
|
type Props = NonNullable<unknown>;
|
|
|
|
|
|
|
|
const VideoPlayer: FC<Props> = ({}) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
const [rate, setRate] = useState(1);
|
|
|
|
const [volume, setVolume] = useState(1);
|
|
|
|
const [muted, setMuted] = useState(false);
|
2024-07-12 15:12:36 +03:30
|
|
|
const [resizeMode, setResizeMode] = useState<EnumValues<ResizeMode>>(
|
|
|
|
ResizeMode.CONTAIN,
|
|
|
|
);
|
2024-07-08 11:24:32 +03:30
|
|
|
const [duration, setDuration] = useState(0);
|
|
|
|
const [currentTime, setCurrentTime] = useState(0);
|
|
|
|
const [_, setVideoSize] = useState({videoWidth: 0, videoHeight: 0});
|
|
|
|
const [paused, setPaused] = useState(false);
|
|
|
|
const [fullscreen, setFullscreen] = useState(true);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);
|
|
|
|
const [textTracks, setTextTracks] = useState<TextTrack[]>([]);
|
|
|
|
const [videoTracks, setVideoTracks] = useState<VideoTrack[]>([]);
|
|
|
|
const [selectedAudioTrack, setSelectedAudioTrack] = useState<
|
|
|
|
SelectedTrack | undefined
|
|
|
|
>(undefined);
|
|
|
|
const [selectedTextTrack, setSelectedTextTrack] = useState<
|
|
|
|
SelectedTrack | undefined
|
|
|
|
>(undefined);
|
|
|
|
const [selectedVideoTrack, setSelectedVideoTrack] =
|
|
|
|
useState<SelectedVideoTrack>({
|
|
|
|
type: SelectedVideoTrackType.AUTO,
|
|
|
|
});
|
|
|
|
const [srcListId, setSrcListId] = useState(0);
|
|
|
|
const [repeat, setRepeat] = useState(false);
|
|
|
|
const [controls, setControls] = useState(false);
|
|
|
|
const [useCache, setUseCache] = useState(false);
|
2024-07-22 22:38:35 +02:00
|
|
|
const [showPoster, setShowPoster] = useState<boolean>(false);
|
2024-07-08 11:24:32 +03:30
|
|
|
const [showNotificationControls, setShowNotificationControls] =
|
|
|
|
useState(false);
|
|
|
|
const [isSeeking, setIsSeeking] = useState(false);
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const videoRef = useRef<VideoRef>(null);
|
2024-07-08 11:24:32 +03:30
|
|
|
const viewStyle = fullscreen ? styles.fullScreen : styles.halfScreen;
|
|
|
|
const currentSrc = srcList[srcListId];
|
2024-06-28 13:03:10 +03:30
|
|
|
const additional = currentSrc as AdditionalSourceInfo;
|
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
const goToChannel = useCallback((channel: number) => {
|
|
|
|
setSrcListId(channel);
|
|
|
|
setDuration(0);
|
|
|
|
setCurrentTime(0);
|
|
|
|
setVideoSize({videoWidth: 0, videoHeight: 0});
|
|
|
|
setIsLoading(false);
|
|
|
|
setAudioTracks([]);
|
|
|
|
setTextTracks([]);
|
|
|
|
setSelectedAudioTrack(undefined);
|
|
|
|
setSelectedTextTrack(undefined);
|
|
|
|
setSelectedVideoTrack({
|
|
|
|
type: SelectedVideoTrackType.AUTO,
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const channelUp = useCallback(() => {
|
|
|
|
console.log('channel up');
|
|
|
|
goToChannel((srcListId + 1) % srcList.length);
|
|
|
|
}, [goToChannel, srcListId]);
|
|
|
|
|
|
|
|
const channelDown = useCallback(() => {
|
|
|
|
console.log('channel down');
|
|
|
|
goToChannel((srcListId + srcList.length - 1) % srcList.length);
|
|
|
|
}, [goToChannel, srcListId]);
|
|
|
|
|
2024-09-04 09:53:30 +02:00
|
|
|
useEffect(() => {
|
2024-09-06 09:45:24 +02:00
|
|
|
if (isAndroid) {
|
|
|
|
NavigationBar.setVisibilityAsync('visible');
|
|
|
|
}
|
2024-09-04 09:53:30 +02:00
|
|
|
}, []);
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioTracks = (data: OnAudioTracksData) => {
|
2024-09-20 16:26:20 +02:00
|
|
|
console.log('onAudioTracks', data);
|
2023-10-26 08:46:04 +02:00
|
|
|
const selectedTrack = data.audioTracks?.find((x: AudioTrack) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
return x.selected;
|
|
|
|
});
|
2024-09-20 16:26:20 +02:00
|
|
|
let value;
|
|
|
|
if (audioTracksSelectionBy === SelectedTrackType.INDEX) {
|
|
|
|
value = selectedTrack?.index;
|
|
|
|
} else if (audioTracksSelectionBy === SelectedTrackType.LANGUAGE) {
|
|
|
|
value = selectedTrack?.language;
|
|
|
|
} else if (audioTracksSelectionBy === SelectedTrackType.TITLE) {
|
|
|
|
value = selectedTrack?.title;
|
2022-04-26 22:59:04 +02:00
|
|
|
}
|
2024-09-20 16:26:20 +02:00
|
|
|
setAudioTracks(data.audioTracks);
|
|
|
|
setSelectedAudioTrack({
|
|
|
|
type: audioTracksSelectionBy,
|
|
|
|
value: value,
|
|
|
|
});
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onVideoTracks = (data: OnVideoTracksData) => {
|
2024-05-22 14:01:55 +02:00
|
|
|
console.log('onVideoTracks', data.videoTracks);
|
2024-07-08 11:24:32 +03:30
|
|
|
setVideoTracks(data.videoTracks);
|
2024-05-22 14:01:55 +02:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onTextTracks = (data: OnTextTracksData) => {
|
2023-10-26 08:46:04 +02:00
|
|
|
const selectedTrack = data.textTracks?.find((x: TextTrack) => {
|
2024-02-29 22:41:04 +09:00
|
|
|
return x?.selected;
|
2023-10-07 23:14:09 +02:00
|
|
|
});
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-09-20 16:26:20 +02:00
|
|
|
setTextTracks(data.textTracks);
|
|
|
|
let value;
|
|
|
|
if (textTracksSelectionBy === SelectedTrackType.INDEX) {
|
|
|
|
value = selectedTrack?.index;
|
|
|
|
} else if (textTracksSelectionBy === SelectedTrackType.LANGUAGE) {
|
|
|
|
value = selectedTrack?.language;
|
|
|
|
} else if (textTracksSelectionBy === SelectedTrackType.TITLE) {
|
|
|
|
value = selectedTrack?.title;
|
2022-04-26 22:59:04 +02:00
|
|
|
}
|
2024-09-20 16:26:20 +02:00
|
|
|
setSelectedTextTrack({
|
|
|
|
type: textTracksSelectionBy,
|
|
|
|
value: value,
|
|
|
|
});
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onLoad = (data: OnLoadData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setDuration(data.duration);
|
2024-06-28 13:03:10 +03:30
|
|
|
onAudioTracks(data);
|
|
|
|
onTextTracks(data);
|
|
|
|
onVideoTracks(data);
|
|
|
|
};
|
|
|
|
|
|
|
|
const onProgress = (data: OnProgressData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setCurrentTime(data.currentTime);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onSeek = (data: OnSeekData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setCurrentTime(data.currentTime);
|
|
|
|
setIsSeeking(false);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onVideoLoadStart = () => {
|
|
|
|
console.log('onVideoLoadStart');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(true);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onTextTrackDataChanged = (data: OnTextTrackDataChangedData) => {
|
2024-02-29 22:41:04 +09:00
|
|
|
console.log(`Subtitles: ${JSON.stringify(data, null, 2)}`);
|
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAspectRatio = (data: OnVideoAspectRatioData) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onAspectRadio called ' + JSON.stringify(data));
|
2024-07-08 11:24:32 +03:30
|
|
|
setVideoSize({videoWidth: data.width, videoHeight: data.height});
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onVideoBuffer = (param: OnBufferData) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onVideoBuffer');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(param.isBuffering);
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onReadyForDisplay = () => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onReadyForDisplay');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(false);
|
2017-01-11 12:51:45 +00:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioBecomingNoisy = () => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setPaused(true);
|
2017-01-11 12:51:45 +00:00
|
|
|
};
|
2015-12-06 22:25:18 -08:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioFocusChanged = (event: OnAudioFocusChangedData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setPaused(!event.hasAudioFocus);
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onError = (err: OnVideoErrorData) => {
|
2023-10-26 08:46:04 +02:00
|
|
|
console.log(JSON.stringify(err));
|
2024-06-28 13:03:10 +03:30
|
|
|
toast(true, 'error: ' + JSON.stringify(err));
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onEnd = () => {
|
2024-07-08 11:24:32 +03:30
|
|
|
if (!repeat) {
|
2024-06-28 13:03:10 +03:30
|
|
|
channelUp();
|
2024-04-26 09:42:21 +02:00
|
|
|
}
|
2022-04-26 22:59:04 +02:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onPlaybackRateChange = (data: OnPlaybackRateChangeData) => {
|
2024-04-04 14:45:39 +02:00
|
|
|
console.log('onPlaybackRateChange', data);
|
2024-04-19 22:38:52 +02:00
|
|
|
};
|
2024-04-04 14:45:39 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onPlaybackStateChanged = (data: OnPlaybackStateChangedData) => {
|
2024-04-04 14:45:39 +02:00
|
|
|
console.log('onPlaybackStateChanged', data);
|
2024-04-19 22:38:52 +02:00
|
|
|
};
|
2024-04-04 14:45:39 +02:00
|
|
|
|
2024-09-03 15:33:43 +02:00
|
|
|
const onVideoBandwidthUpdate = (data: OnBandwidthUpdateData) => {
|
|
|
|
console.log('onVideoBandwidthUpdate', data);
|
2024-09-14 19:53:54 +02:00
|
|
|
};
|
2024-09-03 15:33:43 +02:00
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
const onFullScreenExit = () => {
|
|
|
|
// iOS pauses video on exit from full screen
|
|
|
|
Platform.OS === 'ios' && setPaused(true);
|
2023-11-22 15:03:57 +01:00
|
|
|
};
|
2022-09-11 17:01:53 +02:00
|
|
|
|
2024-09-17 15:58:47 +02:00
|
|
|
const _renderLoader = showPoster ? () => <VideoLoader /> : undefined;
|
|
|
|
|
|
|
|
const _subtitleStyle = {subtitlesFollowVideo: true};
|
|
|
|
const _controlsStyles = {
|
|
|
|
hideNavigationBarOnFullScreenMode: true,
|
|
|
|
hideNotificationBarOnFullScreenMode: true,
|
|
|
|
};
|
|
|
|
const _bufferConfig = {
|
|
|
|
...bufferConfig,
|
|
|
|
cacheSizeMB: useCache ? 200 : 0,
|
2024-09-20 16:26:20 +02:00
|
|
|
};
|
2024-09-17 15:58:47 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
return (
|
|
|
|
<View style={styles.container}>
|
2024-09-04 09:53:30 +02:00
|
|
|
<StatusBar animated={true} backgroundColor="black" hidden={false} />
|
|
|
|
|
2024-07-08 11:24:32 +03:30
|
|
|
{(srcList[srcListId] as AdditionalSourceInfo)?.noView ? null : (
|
2024-06-28 13:03:10 +03:30
|
|
|
<TouchableOpacity style={viewStyle}>
|
|
|
|
<Video
|
2024-07-08 11:24:32 +03:30
|
|
|
showNotificationControls={showNotificationControls}
|
2024-06-28 13:03:10 +03:30
|
|
|
ref={videoRef}
|
|
|
|
source={currentSrc as ReactVideoSource}
|
|
|
|
adTagUrl={additional?.adTagUrl}
|
|
|
|
drm={additional?.drm}
|
|
|
|
style={viewStyle}
|
2024-07-08 11:24:32 +03:30
|
|
|
rate={rate}
|
|
|
|
paused={paused}
|
|
|
|
volume={volume}
|
|
|
|
muted={muted}
|
|
|
|
controls={controls}
|
|
|
|
resizeMode={resizeMode}
|
2024-07-15 23:29:23 +02:00
|
|
|
onFullscreenPlayerWillDismiss={onFullScreenExit}
|
2024-06-28 13:03:10 +03:30
|
|
|
onLoad={onLoad}
|
|
|
|
onAudioTracks={onAudioTracks}
|
|
|
|
onTextTracks={onTextTracks}
|
|
|
|
onVideoTracks={onVideoTracks}
|
|
|
|
onTextTrackDataChanged={onTextTrackDataChanged}
|
|
|
|
onProgress={onProgress}
|
|
|
|
onEnd={onEnd}
|
|
|
|
progressUpdateInterval={1000}
|
|
|
|
onError={onError}
|
|
|
|
onAudioBecomingNoisy={onAudioBecomingNoisy}
|
|
|
|
onAudioFocusChanged={onAudioFocusChanged}
|
|
|
|
onLoadStart={onVideoLoadStart}
|
|
|
|
onAspectRatio={onAspectRatio}
|
|
|
|
onReadyForDisplay={onReadyForDisplay}
|
|
|
|
onBuffer={onVideoBuffer}
|
2024-09-03 15:33:43 +02:00
|
|
|
onBandwidthUpdate={onVideoBandwidthUpdate}
|
2024-06-28 13:03:10 +03:30
|
|
|
onSeek={onSeek}
|
2024-07-08 11:24:32 +03:30
|
|
|
repeat={repeat}
|
|
|
|
selectedTextTrack={selectedTextTrack}
|
|
|
|
selectedAudioTrack={selectedAudioTrack}
|
|
|
|
selectedVideoTrack={selectedVideoTrack}
|
2024-06-28 13:03:10 +03:30
|
|
|
playInBackground={false}
|
2024-09-17 15:58:47 +02:00
|
|
|
bufferConfig={_bufferConfig}
|
2024-06-28 13:03:10 +03:30
|
|
|
preventsDisplaySleepDuringVideoPlayback={true}
|
2024-09-17 15:58:47 +02:00
|
|
|
renderLoader={_renderLoader}
|
2024-06-28 13:03:10 +03:30
|
|
|
onPlaybackRateChange={onPlaybackRateChange}
|
|
|
|
onPlaybackStateChanged={onPlaybackStateChanged}
|
|
|
|
bufferingStrategy={BufferingStrategyType.DEFAULT}
|
|
|
|
debug={{enable: true, thread: true}}
|
2024-09-17 15:58:47 +02:00
|
|
|
subtitleStyle={_subtitleStyle}
|
|
|
|
controlsStyles={_controlsStyles}
|
2024-06-28 13:03:10 +03:30
|
|
|
/>
|
|
|
|
</TouchableOpacity>
|
|
|
|
)}
|
|
|
|
<Overlay
|
|
|
|
channelDown={channelDown}
|
|
|
|
channelUp={channelUp}
|
|
|
|
ref={videoRef}
|
2024-07-08 11:24:32 +03:30
|
|
|
videoTracks={videoTracks}
|
|
|
|
selectedVideoTrack={selectedVideoTrack}
|
|
|
|
setSelectedTextTrack={setSelectedTextTrack}
|
|
|
|
audioTracks={audioTracks}
|
|
|
|
controls={controls}
|
|
|
|
resizeMode={resizeMode}
|
|
|
|
textTracks={textTracks}
|
|
|
|
selectedTextTrack={selectedTextTrack}
|
|
|
|
selectedAudioTrack={selectedAudioTrack}
|
|
|
|
setSelectedAudioTrack={setSelectedAudioTrack}
|
|
|
|
setSelectedVideoTrack={setSelectedVideoTrack}
|
|
|
|
currentTime={currentTime}
|
|
|
|
setMuted={setMuted}
|
|
|
|
muted={muted}
|
|
|
|
duration={duration}
|
|
|
|
paused={paused}
|
|
|
|
volume={volume}
|
|
|
|
setControls={setControls}
|
2024-07-22 22:38:35 +02:00
|
|
|
showPoster={showPoster}
|
2024-07-08 11:24:32 +03:30
|
|
|
rate={rate}
|
|
|
|
setFullscreen={setFullscreen}
|
|
|
|
setPaused={setPaused}
|
|
|
|
isLoading={isLoading}
|
|
|
|
isSeeking={isSeeking}
|
|
|
|
setIsSeeking={setIsSeeking}
|
|
|
|
repeat={repeat}
|
|
|
|
setRepeat={setRepeat}
|
2024-07-22 22:38:35 +02:00
|
|
|
setShowPoster={setShowPoster}
|
2024-07-08 11:24:32 +03:30
|
|
|
setRate={setRate}
|
|
|
|
setResizeMode={setResizeMode}
|
|
|
|
setShowNotificationControls={setShowNotificationControls}
|
|
|
|
showNotificationControls={showNotificationControls}
|
|
|
|
setUseCache={setUseCache}
|
|
|
|
setVolume={setVolume}
|
|
|
|
useCache={useCache}
|
|
|
|
srcListId={srcListId}
|
2024-06-28 13:03:10 +03:30
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
};
|
2023-10-07 23:14:09 +02:00
|
|
|
export default VideoPlayer;
|