Add Play Previous Button
This commit is contained in:
parent
73722a4f00
commit
bd64d5c9ea
3 changed files with 57 additions and 15 deletions
|
@ -6,6 +6,7 @@ import {
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
COLLECTIONS_CONSTS,
|
COLLECTIONS_CONSTS,
|
||||||
makeSelectNextUrlForCollectionAndUrl,
|
makeSelectNextUrlForCollectionAndUrl,
|
||||||
|
makeSelectPreviousUrlForCollectionAndUrl,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doChangeVolume, doChangeMute, doAnalyticsView, doAnalyticsBuffer } from 'redux/actions/app';
|
import { doChangeVolume, doChangeMute, doAnalyticsView, doAnalyticsBuffer } from 'redux/actions/app';
|
||||||
import { selectVolume, selectMute } from 'redux/selectors/app';
|
import { selectVolume, selectMute } from 'redux/selectors/app';
|
||||||
|
@ -33,8 +34,10 @@ const select = (state, props) => {
|
||||||
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId);
|
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId);
|
||||||
|
|
||||||
let playNextUri;
|
let playNextUri;
|
||||||
|
let playPreviousUri;
|
||||||
if (collectionId) {
|
if (collectionId) {
|
||||||
playNextUri = makeSelectNextUrlForCollectionAndUrl(collectionId, props.uri)(state);
|
playNextUri = makeSelectNextUrlForCollectionAndUrl(collectionId, props.uri)(state);
|
||||||
|
playPreviousUri = makeSelectPreviousUrlForCollectionAndUrl(collectionId, props.uri)(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -55,6 +58,7 @@ const select = (state, props) => {
|
||||||
isFloating: makeSelectIsPlayerFloating(props.location)(state),
|
isFloating: makeSelectIsPlayerFloating(props.location)(state),
|
||||||
collectionId,
|
collectionId,
|
||||||
playNextUri,
|
playNextUri,
|
||||||
|
playPreviousUri,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ type Props = {
|
||||||
source: string,
|
source: string,
|
||||||
sourceType: string,
|
sourceType: string,
|
||||||
poster: ?string,
|
poster: ?string,
|
||||||
onPlayerReady: (Player) => void,
|
onPlayerReady: (Player, any) => void,
|
||||||
isAudio: boolean,
|
isAudio: boolean,
|
||||||
startMuted: boolean,
|
startMuted: boolean,
|
||||||
autoplay: boolean,
|
autoplay: boolean,
|
||||||
|
@ -61,6 +61,7 @@ type Props = {
|
||||||
shareTelemetry: boolean,
|
shareTelemetry: boolean,
|
||||||
replay: boolean,
|
replay: boolean,
|
||||||
videoTheaterMode: boolean,
|
videoTheaterMode: boolean,
|
||||||
|
setStartPlayPrevious: (boolean) => void,
|
||||||
setStartPlayNext: (boolean) => void,
|
setStartPlayNext: (boolean) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,6 +107,7 @@ const SMALL_J_KEYCODE = 74;
|
||||||
const SMALL_K_KEYCODE = 75;
|
const SMALL_K_KEYCODE = 75;
|
||||||
const SMALL_L_KEYCODE = 76;
|
const SMALL_L_KEYCODE = 76;
|
||||||
|
|
||||||
|
const P_KEYCODE = 80;
|
||||||
const N_KEYCODE = 78;
|
const N_KEYCODE = 78;
|
||||||
|
|
||||||
const ZERO_KEYCODE = 48;
|
const ZERO_KEYCODE = 48;
|
||||||
|
@ -215,6 +217,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
shareTelemetry,
|
shareTelemetry,
|
||||||
replay,
|
replay,
|
||||||
videoTheaterMode,
|
videoTheaterMode,
|
||||||
|
setStartPlayPrevious,
|
||||||
setStartPlayNext,
|
setStartPlayNext,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -404,6 +407,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey || !e.shiftKey) return;
|
if (e.altKey || e.ctrlKey || e.metaKey || !e.shiftKey) return;
|
||||||
if (e.keyCode === PERIOD_KEYCODE) changePlaybackSpeed(true);
|
if (e.keyCode === PERIOD_KEYCODE) changePlaybackSpeed(true);
|
||||||
if (e.keyCode === COMMA_KEYCODE) changePlaybackSpeed(false);
|
if (e.keyCode === COMMA_KEYCODE) changePlaybackSpeed(false);
|
||||||
|
if (e.keyCode === P_KEYCODE) setStartPlayPrevious(true);
|
||||||
if (e.keyCode === N_KEYCODE) setStartPlayNext(true);
|
if (e.keyCode === N_KEYCODE) setStartPlayNext(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +623,8 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
player.children_[0].setAttribute('playsinline', '');
|
player.children_[0].setAttribute('playsinline', '');
|
||||||
|
|
||||||
// I think this is a callback function
|
// I think this is a callback function
|
||||||
onPlayerReady(player);
|
const videoNode = containerRef.current && containerRef.current.querySelector('video, audio');
|
||||||
|
onPlayerReady(player, videoNode);
|
||||||
});
|
});
|
||||||
|
|
||||||
// pre-roll ads
|
// pre-roll ads
|
||||||
|
|
|
@ -17,6 +17,7 @@ import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
import { addTheaterModeButton } from './internal/theater-mode';
|
import { addTheaterModeButton } from './internal/theater-mode';
|
||||||
import { addPlayNextButton } from './internal/play-next';
|
import { addPlayNextButton } from './internal/play-next';
|
||||||
|
import { addPlayPreviousButton } from './internal/play-previous';
|
||||||
import { useGetAds } from 'effects/use-get-ads';
|
import { useGetAds } from 'effects/use-get-ads';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
|
@ -54,6 +55,7 @@ type Props = {
|
||||||
doSetPlayingUri: (string, string) => void,
|
doSetPlayingUri: (string, string) => void,
|
||||||
doPlayUri: (string) => void,
|
doPlayUri: (string) => void,
|
||||||
playNextUri: string,
|
playNextUri: string,
|
||||||
|
playPreviousUri: string,
|
||||||
authenticated: boolean,
|
authenticated: boolean,
|
||||||
userId: number,
|
userId: number,
|
||||||
homepageData?: { [string]: HomepageCat },
|
homepageData?: { [string]: HomepageCat },
|
||||||
|
@ -94,6 +96,7 @@ function VideoViewer(props: Props) {
|
||||||
doSetPlayingUri,
|
doSetPlayingUri,
|
||||||
doPlayUri,
|
doPlayUri,
|
||||||
playNextUri,
|
playNextUri,
|
||||||
|
playPreviousUri,
|
||||||
homepageData,
|
homepageData,
|
||||||
authenticated,
|
authenticated,
|
||||||
userId,
|
userId,
|
||||||
|
@ -126,6 +129,21 @@ function VideoViewer(props: Props) {
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [replay, setReplay] = useState(false);
|
const [replay, setReplay] = useState(false);
|
||||||
const [startPlayNext, setStartPlayNext] = useState(false);
|
const [startPlayNext, setStartPlayNext] = useState(false);
|
||||||
|
const [startPlayPrevious, setStartPlayPrevious] = useState(false);
|
||||||
|
const [videoNode, setVideoNode] = useState(false);
|
||||||
|
|
||||||
|
const getNavigateUrl = React.useCallback((playUri: string) => {
|
||||||
|
let navigateUrl;
|
||||||
|
if (playUri) {
|
||||||
|
navigateUrl = formatLbryUrlForWeb(playUri);
|
||||||
|
if (collectionId) {
|
||||||
|
const collectionParams = new URLSearchParams();
|
||||||
|
collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId);
|
||||||
|
navigateUrl = navigateUrl + `?` + collectionParams.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return navigateUrl;
|
||||||
|
}, [collectionId]);
|
||||||
|
|
||||||
// force everything to recent when URI changes, can cause weird corner cases otherwise (e.g. navigate while autoplay is true)
|
// force everything to recent when URI changes, can cause weird corner cases otherwise (e.g. navigate while autoplay is true)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -144,18 +162,9 @@ function VideoViewer(props: Props) {
|
||||||
};
|
};
|
||||||
}, [embedded, videoPlaybackRate]);
|
}, [embedded, videoPlaybackRate]);
|
||||||
|
|
||||||
let navigateUrl;
|
|
||||||
if (playNextUri) {
|
|
||||||
navigateUrl = formatLbryUrlForWeb(playNextUri);
|
|
||||||
if (collectionId) {
|
|
||||||
const collectionParams = new URLSearchParams();
|
|
||||||
collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId);
|
|
||||||
navigateUrl = navigateUrl + `?` + collectionParams.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (startPlayNext) {
|
if (startPlayNext) {
|
||||||
|
const navigateUrl = getNavigateUrl(playNextUri);
|
||||||
if (!isFloating && navigateUrl) {
|
if (!isFloating && navigateUrl) {
|
||||||
push(navigateUrl);
|
push(navigateUrl);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +174,26 @@ function VideoViewer(props: Props) {
|
||||||
}
|
}
|
||||||
setStartPlayNext(false);
|
setStartPlayNext(false);
|
||||||
}
|
}
|
||||||
}, [isFloating, navigateUrl, push, doSetPlayingUri, playNextUri, doPlayUri, startPlayNext, collectionId]);
|
if (videoNode) {
|
||||||
|
const currentTime = videoNode.currentTime;
|
||||||
|
|
||||||
|
if (startPlayPrevious) {
|
||||||
|
if (currentTime > 5) {
|
||||||
|
videoNode.currentTime = 0;
|
||||||
|
} else {
|
||||||
|
const navigateUrl = getNavigateUrl(playPreviousUri);
|
||||||
|
if (!isFloating && navigateUrl) {
|
||||||
|
push(navigateUrl);
|
||||||
|
}
|
||||||
|
if (playPreviousUri) {
|
||||||
|
doSetPlayingUri(playPreviousUri, collectionId);
|
||||||
|
doPlayUri(playPreviousUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setStartPlayPrevious(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isFloating, push, doSetPlayingUri, playNextUri, doPlayUri, startPlayNext, collectionId, getNavigateUrl, videoNode, startPlayPrevious, playPreviousUri]);
|
||||||
|
|
||||||
function doTrackingBuffered(e: Event, data: any) {
|
function doTrackingBuffered(e: Event, data: any) {
|
||||||
fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => {
|
fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => {
|
||||||
|
@ -245,13 +273,17 @@ function VideoViewer(props: Props) {
|
||||||
playerReadyDependencyList.push(desktopPlayStartTime);
|
playerReadyDependencyList.push(desktopPlayStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPlayerReady = useCallback((player: Player) => {
|
const onPlayerReady = useCallback((player: Player, videoNode: any) => {
|
||||||
if (!embedded) {
|
if (!embedded) {
|
||||||
|
setVideoNode(videoNode);
|
||||||
player.muted(muted);
|
player.muted(muted);
|
||||||
player.volume(volume);
|
player.volume(volume);
|
||||||
player.playbackRate(videoPlaybackRate);
|
player.playbackRate(videoPlaybackRate);
|
||||||
addTheaterModeButton(player, toggleVideoTheaterMode);
|
addTheaterModeButton(player, toggleVideoTheaterMode);
|
||||||
if (collectionId) addPlayNextButton(player, () => setStartPlayNext(true));
|
if (collectionId) {
|
||||||
|
addPlayNextButton(player, () => setStartPlayNext(true));
|
||||||
|
addPlayPreviousButton(player, () => setStartPlayPrevious(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldPlay = !embedded || autoplayIfEmbedded;
|
const shouldPlay = !embedded || autoplayIfEmbedded;
|
||||||
|
@ -382,6 +414,7 @@ function VideoViewer(props: Props) {
|
||||||
replay={replay}
|
replay={replay}
|
||||||
videoTheaterMode={videoTheaterMode}
|
videoTheaterMode={videoTheaterMode}
|
||||||
setStartPlayNext={setStartPlayNext}
|
setStartPlayNext={setStartPlayNext}
|
||||||
|
setStartPlayPrevious={setStartPlayPrevious}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue