From afcdd2271ea7c0e5738cc627481165fe2fd2ab7c Mon Sep 17 00:00:00 2001 From: 6ea86b96 <6ea86b96@gmail.com> Date: Sun, 11 Jun 2017 00:07:28 +0700 Subject: [PATCH 1/3] Catch and render files with metadata at the end. Also notify if a file is unplayable --- .../video/internal/loading-screen.jsx | 4 +- ui/js/component/video/internal/player.jsx | 81 +++++++++++++++++-- ui/js/component/video/view.jsx | 1 + 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/ui/js/component/video/internal/loading-screen.jsx b/ui/js/component/video/internal/loading-screen.jsx index 2698e824e..3b5f70294 100644 --- a/ui/js/component/video/internal/loading-screen.jsx +++ b/ui/js/component/video/internal/loading-screen.jsx @@ -1,9 +1,9 @@ import React from "react"; -const LoadingScreen = ({ status }) => +const LoadingScreen = ({ status, spinner = true }) =>
-
+ {spinner &&
}
{status} diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index 1910e2a8e..1a86c3b20 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -2,30 +2,97 @@ import React from "react"; import { Thumbnail } from "component/common"; import player from "render-media"; import fs from "fs"; +import LoadingScreen from "./loading-screen"; class VideoPlayer extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + hasMetadata: false, + startedPlaying: false, + unplayable: false, + }; + } + componentDidMount() { - const elem = this.refs.media; + const container = this.refs.media; + const { mediaType } = this.props; + const loadedMetadata = e => { + this.setState({ hasMetadata: true, startedPlaying: true }); + this.refs.media.children[0].play(); + }; + const renderMediaCallback = err => { + if (err) this.setState({ unplayable: true }); + }; + + player.append( + this.file(), + container, + { autoplay: false, controls: true }, + renderMediaCallback.bind(this) + ); + + const mediaElement = this.refs.media.children[0]; + if (mediaElement) { + mediaElement.addEventListener( + "loadedmetadata", + loadedMetadata.bind(this), + { + once: true, + } + ); + } + } + + componentDidUpdate() { + const { mediaType, downloadCompleted } = this.props; + const { startedPlaying } = this.state; + + if (this.playableType() && !startedPlaying && downloadCompleted) { + const container = this.refs.media.children[0]; + + player.render(this.file(), container, { autoplay: true, controls: true }); + } + } + + file() { const { downloadPath, filename } = this.props; - const file = { + + return { name: filename, createReadStream: opts => { return fs.createReadStream(downloadPath, opts); }, }; - player.append(file, elem, { - autoplay: true, - controls: true, - }); + } + + playableType() { + const { mediaType } = this.props; + + return ["audio", "video"].indexOf(mediaType) !== -1; } render() { - const { downloadPath, mediaType, poster } = this.props; + const { mediaType, poster } = this.props; + const { hasMetadata, unplayable } = this.state; + const noMetadataMessage = "Waiting for metadata."; + const unplayableMessage = "Sorry, looks like we can't play this file."; + + const needsMetadata = this.playableType(); return (
{["audio", "application"].indexOf(mediaType) !== -1 && + (!this.playableType() || hasMetadata) && + !unplayable && } + {this.playableType() && + !hasMetadata && + !unplayable && + } + {unplayable && + }
); diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index b5ab5580a..c0a1a4948 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -68,6 +68,7 @@ class Video extends React.PureComponent { poster={poster} downloadPath={fileInfo.download_path} mediaType={mediaType} + downloadCompleted={fileInfo.completed} />)} {!isPlaying &&
Date: Sun, 11 Jun 2017 00:15:47 +0700 Subject: [PATCH 2/3] lock file updates. Are these files more trouble than they're worth? --- app/package-lock.json | 22 +--------------------- ui/package-lock.json | 2 +- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 431a9e6c0..a5eec6773 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.12.0rc6", + "version": "0.12.0", "lockfileVersion": 1, "dependencies": { "commander": { @@ -63,11 +63,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.6.0.tgz", "integrity": "sha1-Umao9J3Zib5Pn2gbbyoMVShdDZo=" }, - "modify-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz", - "integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=" - }, "npm": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/npm/-/npm-4.6.1.tgz", @@ -1456,16 +1451,6 @@ } } }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "pupa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-1.0.0.tgz", - "integrity": "sha1-mpVopa9+ZXuEYqbp1TKHQ1YM7/Y=" - }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -1480,11 +1465,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.1.0.tgz", "integrity": "sha1-yWPc8DciiS7FnLpWnpQLcZVNFyk=" - }, - "unused-filename": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-0.1.0.tgz", - "integrity": "sha1-5fM7yeSmP4f2TTwR0xl53vXS5/s=" } } } diff --git a/ui/package-lock.json b/ui/package-lock.json index 5284b9454..1d2c1b108 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "lbry-web-ui", - "version": "0.12.0rc6", + "version": "0.12.0", "lockfileVersion": 1, "dependencies": { "abbrev": { From 03f0c3ae8f187dae8db563cbba52fd3c541bda25 Mon Sep 17 00:00:00 2001 From: 6ea86b96 <6ea86b96@gmail.com> Date: Sun, 11 Jun 2017 00:17:37 +0700 Subject: [PATCH 3/3] Prettier fixes --- ui/js/actions/cost_info.js | 2 +- ui/js/component/userEmailNew/index.jsx | 26 +++++++++++--------------- ui/js/reducers/claims.js | 12 +++++------- ui/js/selectors/claims.js | 8 ++++---- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/ui/js/actions/cost_info.js b/ui/js/actions/cost_info.js index 9f7506b5f..42025718f 100644 --- a/ui/js/actions/cost_info.js +++ b/ui/js/actions/cost_info.js @@ -12,7 +12,7 @@ export function doFetchCostInfoForUri(uri) { claim = selectClaimsByUri(state)[uri], isGenerous = selectSettingsIsGenerous(state); - if (!claim) return null + if (!claim) return null; function begin() { dispatch({ diff --git a/ui/js/component/userEmailNew/index.jsx b/ui/js/component/userEmailNew/index.jsx index 0b5e93d3e..4040606eb 100644 --- a/ui/js/component/userEmailNew/index.jsx +++ b/ui/js/component/userEmailNew/index.jsx @@ -1,23 +1,19 @@ -import React from 'react' -import { - connect -} from 'react-redux' -import { - doUserEmailNew -} from 'actions/user' +import React from "react"; +import { connect } from "react-redux"; +import { doUserEmailNew } from "actions/user"; import { selectEmailNewIsPending, selectEmailNewErrorMessage, -} from 'selectors/user' -import UserEmailNew from './view' +} from "selectors/user"; +import UserEmailNew from "./view"; -const select = (state) => ({ +const select = state => ({ isPending: selectEmailNewIsPending(state), errorMessage: selectEmailNewErrorMessage(state), -}) +}); -const perform = (dispatch) => ({ - addUserEmail: (email) => dispatch(doUserEmailNew(email)) -}) +const perform = dispatch => ({ + addUserEmail: email => dispatch(doUserEmailNew(email)), +}); -export default connect(select, perform)(UserEmailNew) +export default connect(select, perform)(UserEmailNew); diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index d3cde592e..9cfa92bcb 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -22,9 +22,9 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { return Object.assign({}, state, { byId, - claimsByUri: byUri + claimsByUri: byUri, }); -} +}; reducers[types.RESOLVE_URI_CANCELED] = function(state, action) { const uri = action.data.uri; @@ -42,9 +42,7 @@ reducers[types.FETCH_CLAIM_LIST_MINE_STARTED] = function(state, action) { }; reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { - const { - claims, - } = action.data; + const { claims } = action.data; const myClaims = new Set(state.myClaims); const byUri = Object.assign({}, state.claimsByUri); const byId = Object.assign({}, state.byId); @@ -52,14 +50,14 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { claims.forEach(claim => { myClaims.add(claim.claim_id); byId[claim.claim_id] = claim; - }) + }); return Object.assign({}, state, { isClaimListMinePending: false, myClaims: myClaims, byId, }); -} +}; // reducers[types.FETCH_CHANNEL_CLAIMS_STARTED] = function(state, action) { // const { diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index 11e3b1e86..7508c6ce1 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -5,7 +5,7 @@ const _selectState = state => state.claims || {}; export const selectClaimsById = createSelector( _selectState, - (state) => state.byId || {} + state => state.byId || {} ); export const selectClaimsByUri = createSelector( @@ -28,11 +28,11 @@ export const selectClaimsByUri = createSelector( claims[uri] = claim; } - }) + }); return claims; } -) +); export const selectAllClaimsByChannel = createSelector( _selectState, @@ -107,7 +107,7 @@ export const selectMyClaimsOutpoints = createSelector( claimIds.forEach(claimId => { const claim = byId[claimId]; if (claim) outpoints.push(`${claim.txid}:${claim.nout}`); - }) + }); return outpoints; }