Merge pull request #2235 from lbryio/autoplay

feat: autoplay next file in related list
This commit is contained in:
Sean Yesmunt 2019-01-28 15:30:20 -05:00 committed by GitHub
commit 215a5dc943
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 58 deletions

View file

@ -51,6 +51,7 @@
"flowtype/space-after-type-colon": [2, "always", { "allowLineBreak": true }], "flowtype/space-after-type-colon": [2, "always", { "allowLineBreak": true }],
"no-restricted-syntax": 0, "no-restricted-syntax": 0,
"no-empty": 0, "no-empty": 0,
"react/prefer-stateless-function": 0 "react/prefer-stateless-function": 0,
"react/sort-comp": 0
} }
} }

View file

@ -52,7 +52,7 @@
"hast-util-sanitize": "^1.1.2", "hast-util-sanitize": "^1.1.2",
"keytar": "^4.2.1", "keytar": "^4.2.1",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#a22f8284110f957f3f645d42abc457ab8fb3fa8a", "lbry-redux": "lbryio/lbry-redux#2ff9f70a3d765946a1c83c8e7eee7d81c96c1345",
"lbryinc": "lbryio/lbryinc#83c275da7a44f346ce9e796d06f30126f02b4c63", "lbryinc": "lbryio/lbryinc#83c275da7a44f346ce9e796d06f30126f02b4c63",
"localforage": "^1.7.1", "localforage": "^1.7.1",
"mammoth": "^1.4.6", "mammoth": "^1.4.6",

View file

@ -3,6 +3,7 @@ import * as settings from 'constants/settings';
import { doChangeVolume } from 'redux/actions/app'; import { doChangeVolume } from 'redux/actions/app';
import { selectVolume } from 'redux/selectors/app'; import { selectVolume } from 'redux/selectors/app';
import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content'; import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content';
import { doNavigate } from 'redux/actions/navigation';
import { doClaimEligiblePurchaseRewards } from 'lbryinc'; import { doClaimEligiblePurchaseRewards } from 'lbryinc';
import { import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
@ -13,6 +14,7 @@ import {
makeSelectLoadingForUri, makeSelectLoadingForUri,
makeSelectDownloadingForUri, makeSelectDownloadingForUri,
selectSearchBarFocused, selectSearchBarFocused,
makeSelectFirstRecommendedFileForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
import { selectPlayingUri, makeSelectContentPositionForUri } from 'redux/selectors/content'; import { selectPlayingUri, makeSelectContentPositionForUri } from 'redux/selectors/content';
@ -34,6 +36,7 @@ const select = (state, props) => ({
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state), autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
searchBarFocused: selectSearchBarFocused(state), searchBarFocused: selectSearchBarFocused(state),
fileInfoErrors: selectFileInfoErrors(state), fileInfoErrors: selectFileInfoErrors(state),
nextFileToPlay: makeSelectFirstRecommendedFileForUri(props.uri)(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -43,6 +46,7 @@ const perform = dispatch => ({
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()), claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
savePosition: (claimId, outpoint, position) => savePosition: (claimId, outpoint, position) =>
dispatch(savePosition(claimId, outpoint, position)), dispatch(savePosition(claimId, outpoint, position)),
navigate: (path, params) => dispatch(doNavigate(path, params)),
}); });
export default connect( export default connect(

View file

@ -46,14 +46,15 @@ class MediaPlayer extends React.PureComponent {
volume, volume,
position, position,
claim, claim,
startedPlayingCb, onStartCb,
onFinishCb,
} = this.props; } = this.props;
const loadedMetadata = () => { const loadedMetadata = () => {
this.setState({ hasMetadata: true, startedPlaying: true }); this.setState({ hasMetadata: true, startedPlaying: true });
if (startedPlayingCb) { if (onStartCb) {
startedPlayingCb(); onStartCb();
} }
this.media.children[0].play(); this.media.children[0].play();
}; };
@ -105,6 +106,11 @@ class MediaPlayer extends React.PureComponent {
mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), { mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), {
once: true, once: true,
}); });
mediaElement.addEventListener('ended', () => {
if (onFinishCb) {
onFinishCb();
}
});
mediaElement.addEventListener('webkitfullscreenchange', win32FullScreenChange.bind(this)); mediaElement.addEventListener('webkitfullscreenchange', win32FullScreenChange.bind(this));
mediaElement.addEventListener('volumechange', () => { mediaElement.addEventListener('volumechange', () => {
changeVolume(mediaElement.volume); changeVolume(mediaElement.volume);

View file

@ -1,4 +1,5 @@
// @flow // @flow
import * as PAGES from 'constants/pages';
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import analytics from 'analytics'; import analytics from 'analytics';
@ -42,7 +43,9 @@ type Props = {
searchBarFocused: boolean, searchBarFocused: boolean,
mediaType: string, mediaType: string,
claimRewards: () => void, claimRewards: () => void,
costInfo: ?{ cost: number }, nextFileToPlay: ?string,
navigate: (string, {}) => void,
costInfo: ?{ cost: number }, // eslint-disable-line react/no-unused-prop-types
}; };
class FileViewer extends React.PureComponent<Props> { class FileViewer extends React.PureComponent<Props> {
@ -51,7 +54,8 @@ class FileViewer extends React.PureComponent<Props> {
(this: any).playContent = this.playContent.bind(this); (this: any).playContent = this.playContent.bind(this);
(this: any).handleKeyDown = this.handleKeyDown.bind(this); (this: any).handleKeyDown = this.handleKeyDown.bind(this);
(this: any).logTimeToStart = this.logTimeToStart.bind(this); (this: any).logTimeToStart = this.logTimeToStart.bind(this);
(this: any).startedPlayingCb = undefined; (this: any).onFileFinishCb = this.onFileFinishCb.bind(this);
(this: any).onFileStartCb = undefined;
// Don't add these variables to state because we don't need to re-render when their values change // Don't add these variables to state because we don't need to re-render when their values change
(this: any).startTime = undefined; (this: any).startTime = undefined;
@ -61,7 +65,7 @@ class FileViewer extends React.PureComponent<Props> {
componentDidMount() { componentDidMount() {
const { fileInfo } = this.props; const { fileInfo } = this.props;
if (!fileInfo) { if (!fileInfo) {
this.startedPlayingCb = this.logTimeToStart; this.onFileStartCb = this.logTimeToStart;
} }
this.handleAutoplay(this.props); this.handleAutoplay(this.props);
@ -83,10 +87,10 @@ class FileViewer extends React.PureComponent<Props> {
this.playTime = null; this.playTime = null;
// If this new file is already downloaded, remove the startedPlayingCallback // If this new file is already downloaded, remove the startedPlayingCallback
if (fileInfo && this.startedPlayingCb) { if (fileInfo && this.onFileStartCb) {
this.startedPlayingCb = null; this.onFileStartCb = null;
} else if (!fileInfo && !this.startedPlayingCb) { } else if (!fileInfo && !this.onFileStartCb) {
this.startedPlayingCb = this.logTimeToStart; this.onFileStartCb = this.logTimeToStart;
} }
} }
@ -149,10 +153,10 @@ class FileViewer extends React.PureComponent<Props> {
if (fileInfo || isDownloading || isLoading) { if (fileInfo || isDownloading || isLoading) {
// User may have pressed download before clicking play // User may have pressed download before clicking play
this.startedPlayingCb = null; this.onFileStartCb = null;
} }
if (this.startedPlayingCb) { if (this.onFileStartCb) {
this.startTime = Date.now(); this.startTime = Date.now();
} }
@ -184,7 +188,15 @@ class FileViewer extends React.PureComponent<Props> {
analytics.apiLogView(`${name}#${claimId}`, outpoint, claimId, timeToStart, claimRewards); analytics.apiLogView(`${name}#${claimId}`, outpoint, claimId, timeToStart, claimRewards);
} }
startedPlayingCb: ?() => void; onFileFinishCb() {
// If a user has `autoplay` enabled, start playing the next file at the top of "related"
const { autoplay, nextFileToPlay, navigate } = this.props;
if (autoplay && nextFileToPlay) {
navigate(PAGES.SHOW, { uri: nextFileToPlay });
}
}
onFileStartCb: ?() => void;
startTime: ?number; startTime: ?number;
playTime: ?number; playTime: ?number;
@ -251,7 +263,8 @@ class FileViewer extends React.PureComponent<Props> {
claim={claim} claim={claim}
uri={uri} uri={uri}
position={position} position={position}
startedPlayingCb={this.startedPlayingCb} onStartCb={this.onFileStartCb}
onFinishCb={this.onFileFinishCb}
playingUri={playingUri} playingUri={playingUri}
/> />
)} )}

View file

@ -4,7 +4,6 @@ import type { FileInfo } from 'types/file_info';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import * as settings from 'constants/settings';
import { buildURI, normalizeURI } from 'lbry-redux'; import { buildURI, normalizeURI } from 'lbry-redux';
import FileViewer from 'component/fileViewer'; import FileViewer from 'component/fileViewer';
import Thumbnail from 'component/common/thumbnail'; import Thumbnail from 'component/common/thumbnail';
@ -41,7 +40,6 @@ type Props = {
prepareEdit: ({}, string) => void, prepareEdit: ({}, string) => void,
navigate: (string, ?{}) => void, navigate: (string, ?{}) => void,
openModal: (id: string, { uri: string }) => void, openModal: (id: string, { uri: string }) => void,
setClientSetting: (string, string | boolean | number) => void,
markSubscriptionRead: (string, string) => void, markSubscriptionRead: (string, string) => void,
}; };
@ -59,12 +57,6 @@ class FilePage extends React.Component<Props> {
'application', 'application',
]; ];
constructor(props: Props) {
super(props);
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
}
componentDidMount() { componentDidMount() {
const { uri, fileInfo, fetchFileInfo, fetchCostInfo, setViewed, isSubscribed } = this.props; const { uri, fileInfo, fetchFileInfo, fetchCostInfo, setViewed, isSubscribed } = this.props;
@ -98,10 +90,6 @@ class FilePage extends React.Component<Props> {
} }
} }
onAutoplayChange(event: SyntheticInputEvent<*>) {
this.props.setClientSetting(settings.AUTOPLAY, event.target.checked);
}
removeFromSubscriptionNotifications() { removeFromSubscriptionNotifications() {
// Always try to remove // Always try to remove
// If it doesn't exist, nothing will happen // If it doesn't exist, nothing will happen

View file

@ -287,26 +287,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
</header> </header>
<div className="card__content"> <div className="card__content">
<FormRow>
<FormField
type="checkbox"
name="autoplay"
onChange={this.onAutoplayChange}
checked={autoplay}
postfix={__('Autoplay media files')}
/>
</FormRow>
<FormRow>
<FormField
type="checkbox"
name="auto_download"
onChange={this.onAutoDownloadChange}
checked={autoDownload}
postfix={__('Automatically download new content from your subscriptions')}
/>
</FormRow>
<FormRow> <FormRow>
<FormField <FormField
type="checkbox" type="checkbox"
@ -420,6 +400,39 @@ class SettingsPage extends React.PureComponent<Props, State> {
</div> </div>
</section> </section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Experimental Settings')}</h2>
</header>
<div className="card__content">
<FormRow>
<FormField
type="checkbox"
name="auto_download"
onChange={this.onAutoDownloadChange}
checked={autoDownload}
postfix={__('Automatically download new content from my subscriptions')}
helper={__(
"The latest file from each of your subscriptions will be downloaded for quick access as soon as it's published."
)}
/>
</FormRow>
<FormRow>
<FormField
type="checkbox"
name="autoplay"
onChange={this.onAutoplayChange}
checked={autoplay}
postfix={__('Autoplay media files')}
helper={__(
'Autoplay video and audio files when navigating to a file, as well as the next related item when a file finishes playing.'
)}
/>
</FormRow>
</div>
</section>
<section className="card card--section"> <section className="card card--section">
<header className="card__header"> <header className="card__header">
<h2 className="card__title">{__('Application Cache')}</h2> <h2 className="card__title">{__('Application Cache')}</h2>

View file

@ -18,7 +18,6 @@ import {
makeSelectFileInfoForUri, makeSelectFileInfoForUri,
selectFileInfosByOutpoint, selectFileInfosByOutpoint,
selectDownloadingByOutpoint, selectDownloadingByOutpoint,
selectTotalDownloadProgress,
selectBalance, selectBalance,
makeSelectChannelForClaimUri, makeSelectChannelForClaimUri,
parseURI, parseURI,
@ -27,7 +26,6 @@ import {
} from 'lbry-redux'; } from 'lbry-redux';
import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings';
import setBadge from 'util/set-badge'; import setBadge from 'util/set-badge';
import setProgressBar from 'util/set-progress-bar';
import analytics from 'analytics'; import analytics from 'analytics';
const DOWNLOAD_POLL_INTERVAL = 250; const DOWNLOAD_POLL_INTERVAL = 250;
@ -66,8 +64,10 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) {
const badgeNumber = selectBadgeNumber(state); const badgeNumber = selectBadgeNumber(state);
setBadge(badgeNumber === 0 ? '' : `${badgeNumber}`); setBadge(badgeNumber === 0 ? '' : `${badgeNumber}`);
const totalProgress = selectTotalDownloadProgress(state); // Disabling this for now because it's confusing for new users that don't realize files are actually being downloaded
setProgressBar(totalProgress); // This should move inside of the app
// const totalProgress = selectTotalDownloadProgress(state);
// setProgressBar(totalProgress);
const channelUri = makeSelectChannelForClaimUri(uri, true)(state); const channelUri = makeSelectChannelForClaimUri(uri, true)(state);
const { claimName: channelName } = parseURI(channelUri); const { claimName: channelName } = parseURI(channelUri);
@ -120,8 +120,8 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) {
}, },
}); });
const totalProgress = selectTotalDownloadProgress(getState()); // const totalProgress = selectTotalDownloadProgress(getState());
setProgressBar(totalProgress); // setProgressBar(totalProgress);
setNextStatusUpdate(); setNextStatusUpdate();
} }
}); });

View file

@ -5723,17 +5723,17 @@ lazy-val@^1.0.3:
tar-stream "^1.6.2" tar-stream "^1.6.2"
zstd-codec "^0.1.1" zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404: lbry-redux@lbryio/lbry-redux#2ff9f70a3d765946a1c83c8e7eee7d81c96c1345:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/84b7d396934d57a37802aadbef71db91230a9404" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/2ff9f70a3d765946a1c83c8e7eee7d81c96c1345"
dependencies: dependencies:
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"
reselect "^3.0.0" reselect "^3.0.0"
uuid "^3.3.2" uuid "^3.3.2"
lbry-redux@lbryio/lbry-redux#a22f8284110f957f3f645d42abc457ab8fb3fa8a: lbry-redux@lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/a22f8284110f957f3f645d42abc457ab8fb3fa8a" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/84b7d396934d57a37802aadbef71db91230a9404"
dependencies: dependencies:
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"
reselect "^3.0.0" reselect "^3.0.0"