Add Play Next Button
This commit is contained in:
parent
ec6f9c8a7f
commit
b26255bf53
3 changed files with 71 additions and 3 deletions
|
@ -1,9 +1,20 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri, SETTINGS } from 'lbry-redux';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectThumbnailForUri,
|
||||
SETTINGS,
|
||||
COLLECTIONS_CONSTS,
|
||||
makeSelectNextUrlForCollectionAndUrl,
|
||||
} from 'lbry-redux';
|
||||
import { doChangeVolume, doChangeMute, doAnalyticsView, doAnalyticsBuffer } from 'redux/actions/app';
|
||||
import { selectVolume, selectMute } from 'redux/selectors/app';
|
||||
import { savePosition, clearPosition } from 'redux/actions/content';
|
||||
import { makeSelectContentPositionForUri } from 'redux/selectors/content';
|
||||
import { savePosition, clearPosition, doSetPlayingUri, doPlayUri } from 'redux/actions/content';
|
||||
import {
|
||||
makeSelectContentPositionForUri,
|
||||
selectPlayingUri,
|
||||
makeSelectIsPlayerFloating,
|
||||
} from 'redux/selectors/content';
|
||||
import VideoViewer from './view';
|
||||
import { withRouter } from 'react-router';
|
||||
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
||||
|
@ -18,6 +29,13 @@ const select = (state, props) => {
|
|||
// TODO: eventually this should be received from DB and not local state (https://github.com/lbryio/lbry-desktop/issues/6796)
|
||||
const position = urlParams.get('t') !== null ? urlParams.get('t') : makeSelectContentPositionForUri(props.uri)(state);
|
||||
const userId = selectUser(state) && selectUser(state).id;
|
||||
const playingUri = selectPlayingUri(state);
|
||||
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId);
|
||||
|
||||
let playNextUri;
|
||||
if (collectionId) {
|
||||
playNextUri = makeSelectNextUrlForCollectionAndUrl(collectionId, props.uri)(state);
|
||||
}
|
||||
|
||||
return {
|
||||
autoplayIfEmbedded: Boolean(autoplay),
|
||||
|
@ -34,6 +52,9 @@ const select = (state, props) => {
|
|||
userId: userId,
|
||||
shareTelemetry: IS_WEB || selectDaemonSettings(state).share_usage_data,
|
||||
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||
isFloating: makeSelectIsPlayerFloating(props.location)(state),
|
||||
collectionId,
|
||||
playNextUri,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -47,6 +68,8 @@ const perform = (dispatch) => ({
|
|||
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
||||
toggleVideoTheaterMode: () => dispatch(toggleVideoTheaterMode()),
|
||||
setVideoPlaybackRate: (rate) => dispatch(doSetClientSetting(SETTINGS.VIDEO_PLAYBACK_RATE, rate)),
|
||||
doSetPlayingUri: (uri, collectionId) => dispatch(doSetPlayingUri({ uri, collectionId })),
|
||||
doPlayUri: (uri) => dispatch(doPlayUri(uri)),
|
||||
});
|
||||
|
||||
export default withRouter(connect(select, perform)(VideoViewer));
|
||||
|
|
|
@ -61,6 +61,7 @@ type Props = {
|
|||
shareTelemetry: boolean,
|
||||
replay: boolean,
|
||||
videoTheaterMode: boolean,
|
||||
setStartPlayNext: (boolean) => void,
|
||||
};
|
||||
|
||||
// type VideoJSOptions = {
|
||||
|
@ -105,6 +106,8 @@ const SMALL_J_KEYCODE = 74;
|
|||
const SMALL_K_KEYCODE = 75;
|
||||
const SMALL_L_KEYCODE = 76;
|
||||
|
||||
const N_KEYCODE = 78;
|
||||
|
||||
const ZERO_KEYCODE = 48;
|
||||
const ONE_KEYCODE = 49;
|
||||
const TWO_KEYCODE = 50;
|
||||
|
@ -212,6 +215,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
|||
shareTelemetry,
|
||||
replay,
|
||||
videoTheaterMode,
|
||||
setStartPlayNext,
|
||||
} = props;
|
||||
|
||||
const [reload, setReload] = useState('initial');
|
||||
|
@ -399,6 +403,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
|||
if (e.altKey || e.ctrlKey || e.metaKey || !e.shiftKey) return;
|
||||
if (e.keyCode === PERIOD_KEYCODE) changePlaybackSpeed(true);
|
||||
if (e.keyCode === COMMA_KEYCODE) changePlaybackSpeed(false);
|
||||
if (e.keyCode === N_KEYCODE) setStartPlayNext(true);
|
||||
}
|
||||
|
||||
function handleSingleKeyActions(e: KeyboardEvent) {
|
||||
|
|
|
@ -16,12 +16,15 @@ import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
|
|||
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
||||
import LoadingScreen from 'component/common/loading-screen';
|
||||
import { addTheaterModeButton } from './internal/theater-mode';
|
||||
import { addPlayNextButton } from './internal/play-next';
|
||||
import { useGetAds } from 'effects/use-get-ads';
|
||||
import Button from 'component/button';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import { useHistory } from 'react-router';
|
||||
import { getAllIds } from 'util/buildHomepage';
|
||||
import type { HomepageCat } from 'util/buildHomepage';
|
||||
import { formatLbryUrlForWeb } from 'util/url';
|
||||
import { COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||
|
||||
const PLAY_TIMEOUT_ERROR = 'play_timeout_error';
|
||||
const PLAY_TIMEOUT_LIMIT = 2000;
|
||||
|
@ -48,11 +51,16 @@ type Props = {
|
|||
clearPosition: (string) => void,
|
||||
toggleVideoTheaterMode: () => void,
|
||||
setVideoPlaybackRate: (number) => void,
|
||||
doSetPlayingUri: (string, string) => void,
|
||||
doPlayUri: (string) => void,
|
||||
playNextUri: string,
|
||||
authenticated: boolean,
|
||||
userId: number,
|
||||
homepageData?: { [string]: HomepageCat },
|
||||
shareTelemetry: boolean,
|
||||
videoTheaterMode: boolean,
|
||||
collectionId: string,
|
||||
isFloating: boolean,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -83,11 +91,16 @@ function VideoViewer(props: Props) {
|
|||
desktopPlayStartTime,
|
||||
toggleVideoTheaterMode,
|
||||
setVideoPlaybackRate,
|
||||
doSetPlayingUri,
|
||||
doPlayUri,
|
||||
playNextUri,
|
||||
homepageData,
|
||||
authenticated,
|
||||
userId,
|
||||
shareTelemetry,
|
||||
videoTheaterMode,
|
||||
collectionId,
|
||||
isFloating,
|
||||
} = props;
|
||||
|
||||
const adApprovedChannelIds = homepageData ? getAllIds(homepageData) : [];
|
||||
|
@ -97,6 +110,7 @@ function VideoViewer(props: Props) {
|
|||
const forcePlayer = FORCE_CONTENT_TYPE_PLAYER.includes(contentType);
|
||||
const {
|
||||
location: { pathname },
|
||||
push,
|
||||
} = useHistory();
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [showAutoplayCountdown, setShowAutoplayCountdown] = useState(false);
|
||||
|
@ -111,6 +125,7 @@ function VideoViewer(props: Props) {
|
|||
breaks because some browsers (e.g. Firefox) block autoplay but leave the player.play Promise pending */
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [replay, setReplay] = useState(false);
|
||||
const [startPlayNext, setStartPlayNext] = useState(false);
|
||||
|
||||
// force everything to recent when URI changes, can cause weird corner cases otherwise (e.g. navigate while autoplay is true)
|
||||
useEffect(() => {
|
||||
|
@ -129,6 +144,29 @@ function VideoViewer(props: Props) {
|
|||
};
|
||||
}, [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(() => {
|
||||
if (startPlayNext) {
|
||||
if (!isFloating && navigateUrl) {
|
||||
push(navigateUrl);
|
||||
}
|
||||
if (playNextUri) {
|
||||
doSetPlayingUri(playNextUri, collectionId);
|
||||
doPlayUri(playNextUri);
|
||||
}
|
||||
setStartPlayNext(false);
|
||||
}
|
||||
}, [isFloating, navigateUrl, push, doSetPlayingUri, playNextUri, doPlayUri, startPlayNext, collectionId]);
|
||||
|
||||
function doTrackingBuffered(e: Event, data: any) {
|
||||
fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => {
|
||||
data.playerPoweredBy = response.headers.get('x-powered-by');
|
||||
|
@ -213,6 +251,7 @@ function VideoViewer(props: Props) {
|
|||
player.volume(volume);
|
||||
player.playbackRate(videoPlaybackRate);
|
||||
addTheaterModeButton(player, toggleVideoTheaterMode);
|
||||
if (collectionId) addPlayNextButton(player, () => setStartPlayNext(true));
|
||||
}
|
||||
|
||||
const shouldPlay = !embedded || autoplayIfEmbedded;
|
||||
|
@ -342,6 +381,7 @@ function VideoViewer(props: Props) {
|
|||
shareTelemetry={shareTelemetry}
|
||||
replay={replay}
|
||||
videoTheaterMode={videoTheaterMode}
|
||||
setStartPlayNext={setStartPlayNext}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue