Merge pull request #2901 from lbryio/playerStuff

Autoplay next in list, without duplicates.
This commit is contained in:
jessopb 2019-09-17 21:11:22 -04:00 committed by GitHub
commit cb28b24b6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 6 deletions

View file

@ -8,8 +8,9 @@ import {
makeSelectDownloadPathForUri, makeSelectDownloadPathForUri,
makeSelectFileNameForUri, makeSelectFileNameForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { THEME } from 'constants/settings'; import { THEME, AUTOPLAY } from 'constants/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectNextUnplayedRecommended } from 'redux/selectors/content';
import FileRender from './view'; import FileRender from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -21,6 +22,8 @@ const select = (state, props) => ({
downloadPath: makeSelectDownloadPathForUri(props.uri)(state), downloadPath: makeSelectDownloadPathForUri(props.uri)(state),
fileName: makeSelectFileNameForUri(props.uri)(state), fileName: makeSelectFileNameForUri(props.uri)(state),
streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state),
autoplay: makeSelectClientSetting(AUTOPLAY)(state),
nextUnplayed: makeSelectNextUnplayedRecommended(props.uri)(state),
}); });
export default connect(select)(FileRender); export default connect(select)(FileRender);

View file

@ -6,6 +6,8 @@ import VideoViewer from 'component/viewers/videoViewer';
import ImageViewer from 'component/viewers/imageViewer'; import ImageViewer from 'component/viewers/imageViewer';
import AppViewer from 'component/viewers/appViewer'; import AppViewer from 'component/viewers/appViewer';
import Button from 'component/button'; import Button from 'component/button';
import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri';
// @if TARGET='web' // @if TARGET='web'
import { generateStreamUrl } from 'util/lbrytv'; import { generateStreamUrl } from 'util/lbrytv';
// @endif // @endif
@ -67,6 +69,10 @@ type Props = {
currentTheme: string, currentTheme: string,
downloadPath: string, downloadPath: string,
fileName: string, fileName: string,
autoplay: boolean,
nextFileToPlay: string,
nextUnplayed: string,
history: { push: string => void },
}; };
class FileRender extends React.PureComponent<Props> { class FileRender extends React.PureComponent<Props> {
@ -74,6 +80,7 @@ class FileRender extends React.PureComponent<Props> {
super(props); super(props);
(this: any).escapeListener = this.escapeListener.bind(this); (this: any).escapeListener = this.escapeListener.bind(this);
(this: any).onEndedCb = this.onEndedCb.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -98,6 +105,13 @@ class FileRender extends React.PureComponent<Props> {
remote.getCurrentWindow().setFullScreen(false); remote.getCurrentWindow().setFullScreen(false);
} }
onEndedCb() {
const { autoplay, nextUnplayed, history } = this.props;
if (autoplay && nextUnplayed) {
history.push(formatLbryUriForWeb(nextUnplayed));
}
}
renderViewer() { renderViewer() {
const { mediaType, currentTheme, claim, contentType, downloadPath, fileName, streamingUrl, uri } = this.props; const { mediaType, currentTheme, claim, contentType, downloadPath, fileName, streamingUrl, uri } = this.props;
const fileType = fileName && path.extname(fileName).substring(1); const fileType = fileName && path.extname(fileName).substring(1);
@ -117,8 +131,8 @@ class FileRender extends React.PureComponent<Props> {
application: <AppViewer uri={uri} />, application: <AppViewer uri={uri} />,
// @endif // @endif
video: <VideoViewer uri={uri} source={source} contentType={contentType} />, video: <VideoViewer uri={uri} source={source} contentType={contentType} onEndedCB={this.onEndedCb} />,
audio: <VideoViewer uri={uri} source={source} contentType={contentType} />, audio: <VideoViewer uri={uri} source={source} contentType={contentType} onEndedCB={this.onEndedCb} />,
image: <ImageViewer uri={uri} source={source} />, image: <ImageViewer uri={uri} source={source} />,
// Add routes to viewer... // Add routes to viewer...
}; };
@ -201,4 +215,4 @@ class FileRender extends React.PureComponent<Props> {
} }
} }
export default FileRender; export default withRouter(FileRender);

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { makeSelectFileInfoForUri } from 'lbry-redux'; import { makeSelectFileInfoForUri } from 'lbry-redux';
import { doChangeVolume, doChangeMute } from 'redux/actions/app'; import { doChangeVolume, doChangeMute } from 'redux/actions/app';
import { selectVolume, selectMute } from 'redux/selectors/app'; import { selectVolume, selectMute } from 'redux/selectors/app';
import { savePosition } from 'redux/actions/content'; import { savePosition, doSetPlayingUri } from 'redux/actions/content';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
import VideoViewer from './view'; import VideoViewer from './view';
@ -17,6 +17,7 @@ const perform = dispatch => ({
changeVolume: volume => dispatch(doChangeVolume(volume)), changeVolume: volume => dispatch(doChangeVolume(volume)),
savePosition: (uri, position) => dispatch(savePosition(uri, position)), savePosition: (uri, position) => dispatch(savePosition(uri, position)),
changeMute: muted => dispatch(doChangeMute(muted)), changeMute: muted => dispatch(doChangeMute(muted)),
setPlayingUri: uri => dispatch(doSetPlayingUri(uri)),
}); });
export default connect( export default connect(

View file

@ -14,16 +14,55 @@ const VIDEO_JS_OPTIONS = {
}; };
type Props = { type Props = {
volume: number,
position: number,
muted: boolean,
hasFileInfo: boolean,
changeVolume: number => void,
savePosition: (string, number) => void,
changeMute: boolean => void,
setPlayingUri: (string | null) => void,
source: string, source: string,
contentType: string, contentType: string,
hasFileInfo: boolean, hasFileInfo: boolean,
onEndedCB: any,
}; };
function VideoViewer(props: Props) { function VideoViewer(props: Props) {
const { contentType, source } = props; const { contentType, source, setPlayingUri, onEndedCB } = props;
const videoRef = useRef(); const videoRef = useRef();
const [requireRedraw, setRequireRedraw] = useState(false); const [requireRedraw, setRequireRedraw] = useState(false);
useEffect(() => {
const currentVideo: HTMLVideoElement | null = document.querySelector('video');
function doEnded() {
// clear position
setPlayingUri(null);
onEndedCB();
}
function doPause(e: Event) {
// store position e.target.currentTime
}
function doVolume(e: Event) {
// store volume e.target.volume
}
if (currentVideo) {
currentVideo.addEventListener('ended', doEnded);
currentVideo.addEventListener('pause', doPause);
currentVideo.addEventListener('volumechange', doVolume);
}
// cleanup function:
return () => {
if (currentVideo) {
currentVideo.removeEventListener('ended', doEnded);
currentVideo.removeEventListener('pause', doPause);
currentVideo.removeEventListener('volumechange', doVolume);
}
};
}, []);
useEffect(() => { useEffect(() => {
const videoNode = videoRef.current; const videoNode = videoRef.current;
const videoJsOptions = { const videoJsOptions = {

View file

@ -5,6 +5,7 @@ import {
selectClaimsByUri, selectClaimsByUri,
makeSelectClaimsInChannelForCurrentPageState, makeSelectClaimsInChannelForCurrentPageState,
makeSelectClaimIsNsfw, makeSelectClaimIsNsfw,
makeSelectRecommendedContentForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectShowMatureContent } from 'redux/selectors/settings'; import { selectShowMatureContent } from 'redux/selectors/settings';
@ -76,6 +77,21 @@ export const makeSelectHasVisitedUri = (uri: string) =>
history => Boolean(history) history => Boolean(history)
); );
export const makeSelectNextUnplayedRecommended = (uri: string) =>
createSelector(
makeSelectRecommendedContentForUri(uri),
selectHistory,
(possibleNext, history) => {
if (possibleNext) {
for (let i = 0; i < possibleNext.length; i++) {
if (!history.find(item => item.uri === possibleNext[i])) {
return possibleNext[i];
}
}
}
}
);
export const selectRecentHistory = createSelector( export const selectRecentHistory = createSelector(
selectHistory, selectHistory,
history => { history => {