diff --git a/src/ui/component/fileRender/index.js b/src/ui/component/fileRender/index.js index d61441e01..189d23550 100644 --- a/src/ui/component/fileRender/index.js +++ b/src/ui/component/fileRender/index.js @@ -8,8 +8,9 @@ import { makeSelectDownloadPathForUri, makeSelectFileNameForUri, } from 'lbry-redux'; -import { THEME } from 'constants/settings'; +import { THEME, AUTOPLAY } from 'constants/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings'; +import { makeSelectNextUnplayedRecommended } from 'redux/selectors/content'; import FileRender from './view'; const select = (state, props) => ({ @@ -21,6 +22,8 @@ const select = (state, props) => ({ downloadPath: makeSelectDownloadPathForUri(props.uri)(state), fileName: makeSelectFileNameForUri(props.uri)(state), streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), + autoplay: makeSelectClientSetting(AUTOPLAY)(state), + nextUnplayed: makeSelectNextUnplayedRecommended(props.uri)(state), }); export default connect(select)(FileRender); diff --git a/src/ui/component/fileRender/view.jsx b/src/ui/component/fileRender/view.jsx index 024cbfb6f..ddc831c2e 100644 --- a/src/ui/component/fileRender/view.jsx +++ b/src/ui/component/fileRender/view.jsx @@ -6,6 +6,8 @@ import VideoViewer from 'component/viewers/videoViewer'; import ImageViewer from 'component/viewers/imageViewer'; import AppViewer from 'component/viewers/appViewer'; import Button from 'component/button'; +import { withRouter } from 'react-router-dom'; +import { formatLbryUriForWeb } from 'util/uri'; // @if TARGET='web' import { generateStreamUrl } from 'util/lbrytv'; // @endif @@ -67,6 +69,10 @@ type Props = { currentTheme: string, downloadPath: string, fileName: string, + autoplay: boolean, + nextFileToPlay: string, + nextUnplayed: string, + history: { push: string => void }, }; class FileRender extends React.PureComponent { @@ -74,6 +80,7 @@ class FileRender extends React.PureComponent { super(props); (this: any).escapeListener = this.escapeListener.bind(this); + (this: any).onEndedCb = this.onEndedCb.bind(this); } componentDidMount() { @@ -98,6 +105,13 @@ class FileRender extends React.PureComponent { remote.getCurrentWindow().setFullScreen(false); } + onEndedCb() { + const { autoplay, nextUnplayed, history } = this.props; + if (autoplay && nextUnplayed) { + history.push(formatLbryUriForWeb(nextUnplayed)); + } + } + renderViewer() { const { mediaType, currentTheme, claim, contentType, downloadPath, fileName, streamingUrl, uri } = this.props; const fileType = fileName && path.extname(fileName).substring(1); @@ -117,8 +131,8 @@ class FileRender extends React.PureComponent { application: , // @endif - video: , - audio: , + video: , + audio: , image: , // Add routes to viewer... }; @@ -201,4 +215,4 @@ class FileRender extends React.PureComponent { } } -export default FileRender; +export default withRouter(FileRender); diff --git a/src/ui/component/viewers/videoViewer/index.js b/src/ui/component/viewers/videoViewer/index.js index 0f84ca5a3..1238ee8a4 100644 --- a/src/ui/component/viewers/videoViewer/index.js +++ b/src/ui/component/viewers/videoViewer/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { makeSelectFileInfoForUri } from 'lbry-redux'; import { doChangeVolume, doChangeMute } from 'redux/actions/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 VideoViewer from './view'; @@ -17,6 +17,7 @@ const perform = dispatch => ({ changeVolume: volume => dispatch(doChangeVolume(volume)), savePosition: (uri, position) => dispatch(savePosition(uri, position)), changeMute: muted => dispatch(doChangeMute(muted)), + setPlayingUri: uri => dispatch(doSetPlayingUri(uri)), }); export default connect( diff --git a/src/ui/component/viewers/videoViewer/view.jsx b/src/ui/component/viewers/videoViewer/view.jsx index e38fbcb35..ac90cf0aa 100644 --- a/src/ui/component/viewers/videoViewer/view.jsx +++ b/src/ui/component/viewers/videoViewer/view.jsx @@ -14,16 +14,55 @@ const VIDEO_JS_OPTIONS = { }; 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, contentType: string, hasFileInfo: boolean, + onEndedCB: any, }; function VideoViewer(props: Props) { - const { contentType, source } = props; + const { contentType, source, setPlayingUri, onEndedCB } = props; const videoRef = useRef(); 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(() => { const videoNode = videoRef.current; const videoJsOptions = { diff --git a/src/ui/redux/selectors/content.js b/src/ui/redux/selectors/content.js index 1c99061b1..5c2d6c5db 100644 --- a/src/ui/redux/selectors/content.js +++ b/src/ui/redux/selectors/content.js @@ -5,6 +5,7 @@ import { selectClaimsByUri, makeSelectClaimsInChannelForCurrentPageState, makeSelectClaimIsNsfw, + makeSelectRecommendedContentForUri, } from 'lbry-redux'; import { selectShowMatureContent } from 'redux/selectors/settings'; @@ -76,6 +77,21 @@ export const makeSelectHasVisitedUri = (uri: string) => 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( selectHistory, history => {