From cdf37977080f2776bbe2e498f1e6585df4b56bca Mon Sep 17 00:00:00 2001 From: 6ea86b96 <6ea86b96@gmail.com> Date: Tue, 23 May 2017 22:08:58 +0400 Subject: [PATCH] Messing around with an audio player --- ui/js/component/audio/index.js | 53 +++++++++ ui/js/component/audio/view.jsx | 211 +++++++++++++++++++++++++++++++++ ui/js/page/filePage/view.jsx | 19 ++- ui/package.json | 3 +- 4 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 ui/js/component/audio/index.js create mode 100644 ui/js/component/audio/view.jsx diff --git a/ui/js/component/audio/index.js b/ui/js/component/audio/index.js new file mode 100644 index 000000000..9d9a334ec --- /dev/null +++ b/ui/js/component/audio/index.js @@ -0,0 +1,53 @@ +import React from 'react' +import { + connect, +} from 'react-redux' +import { + doCloseModal, +} from 'actions/app' +import { + selectCurrentModal, +} from 'selectors/app' +import { + doPurchaseUri, + doLoadVideo, +} from 'actions/content' +import { + makeSelectMetadataForUri +} from 'selectors/claims' +import { + makeSelectFileInfoForUri, + makeSelectLoadingForUri, + makeSelectDownloadingForUri, +} from 'selectors/file_info' +import { + makeSelectCostInfoForUri, +} from 'selectors/cost_info' +import Audio from './view' + +const makeSelect = () => { + const selectCostInfo = makeSelectCostInfoForUri() + const selectFileInfo = makeSelectFileInfoForUri() + const selectIsLoading = makeSelectLoadingForUri() + const selectIsDownloading = makeSelectDownloadingForUri() + const selectMetadata = makeSelectMetadataForUri() + + const select = (state, props) => ({ + costInfo: selectCostInfo(state, props), + fileInfo: selectFileInfo(state, props), + metadata: selectMetadata(state, props), + modal: selectCurrentModal(state), + isLoading: selectIsLoading(state, props), + isDownloading: selectIsDownloading(state, props), + }) + + return select +} + +const perform = (dispatch) => ({ + loadVideo: (uri) => dispatch(doLoadVideo(uri)), + purchaseUri: (uri) => dispatch(doPurchaseUri(uri)), + closeModal: () => dispatch(doCloseModal()), +}) + +export default connect(makeSelect, perform)(Audio) diff --git a/ui/js/component/audio/view.jsx b/ui/js/component/audio/view.jsx new file mode 100644 index 000000000..2e30c9d45 --- /dev/null +++ b/ui/js/component/audio/view.jsx @@ -0,0 +1,211 @@ +import React from 'react' +import { + Thumbnail, +} from 'component/common' +import Link from 'component/link' +import Modal from 'component/modal' +import FilePrice from 'component/filePrice' +import lbry from 'lbry' + +const WaveSurfer = require('wavesurfer.js') + +class PlayButton extends React.Component { + onPurchaseConfirmed() { + this.props.closeModal() + this.props.startPlaying() + this.props.loadVideo(this.props.uri) + } + + onPlayClick() { + this.props.purchaseUri(this.props.uri).then(() => { + if (!this.props.modal) { + this.props.startPlaying() + } + }) + } + + render() { + const { + button, + label, + className, + metadata, + metadata: { + title, + }, + uri, + modal, + closeModal, + isLoading, + costInfo, + fileInfo, + } = this.props + + return (
+ + {modal} + { this.closeModal() }}> + You don't have enough LBRY credits to pay for this stream. + + + This will purchase {title} for credits. + + { this.closeModal() }} contentLabel="Timed Out"> + Sorry, your download timed out :( + +
); + } +} + +class Audio extends React.Component { + constructor(props) { + super(props) + this.state = { isPlaying: false } + } + + startPlaying() { + this.setState({ + isPlaying: true + }) + } + + render() { + const { + metadata, + fileInfo, + isLoading, + isDownloading, + } = this.props + const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0 + const { + isPlaying = false, + } = this.state + + let loadStatusMessage + if (isLoading) { + loadStatusMessage = "Requesting stream... it may sit here for like 15-20 seconds in a really awkward way... we're working on it" + } else if (isDownloading) { + loadStatusMessage = "Downloading stream... not long left now!" + } + + return ( +
+
+ {metadata && !!metadata.thumbnail ? : + } +
+ {(isPlaying || isLoading) && isReadyToPlay && + } + {(isPlaying || isLoading) && !isReadyToPlay && + this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
} + {!isPlaying && !isLoading && +
+
+ +
+
+ } +
+ ) + } +} + +class AudioPlayer extends React.PureComponent { + constructor(props) { + super(props) + + this.state = { + wavesurfer: null, + } + } + + componentDidMount() { + const elem = this.refs['audio-player'] + const { + downloadPath, + } = this.props + const wavesurfer = WaveSurfer.create({ + container: elem, + progressColor: 'darkslategray', + height: 96, + }) + const playingStarted = this.playingStarted.bind(this) + const playingPaused = this.paused.bind(this) + wavesurfer.on('play', playingStarted) + wavesurfer.on('pause', playingPaused) + wavesurfer.on('ready', () => wavesurfer.play()) + this.setState({ + wavesurfer, + }) + // setTimeout(() => wavesurfer.play(), 1000) + wavesurfer.load(downloadPath) + } + + componentWillUnmount() { + this.pause() + } + + playingStarted() { + this.setState({ + isPlaying: true, + }) + } + + paused() { + this.setState({ + isPlaying: false, + }) + } + + pause() { + this.state.wavesurfer.pause() + } + + play() { + this.state.wavesurfer.play() + } + + render() { + const { + isPlaying, + } = this.state + + return( +
+
+
+
+
+
+
+
+ {isPlaying && + } + {!isPlaying && + } +
+
+
+ ) + } +} + +export default Audio diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index 2373588b7..8a0041212 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -2,6 +2,7 @@ import React from 'react'; import lbry from 'lbry.js'; import lbryuri from 'lbryuri.js'; import Video from 'component/video' +import Audio from 'component/audio' import { Thumbnail, } from 'component/common'; @@ -85,13 +86,25 @@ class FilePage extends React.Component{ const channelClaimId = claim.value && claim.value.publisherSignature ? claim.value.publisherSignature.certificateId : null; const channelUri = signatureIsValid && hasSignature && channelName ? lbryuri.build({channelName, claimId: channelClaimId}, false) : null const uriIndicator = + const playableContent = contentType && (contentType.startsWith('video/') || contentType.startsWith('audio/')) return (
- { contentType && contentType.startsWith('video/') ? -
diff --git a/ui/package.json b/ui/package.json index 6245fcd89..c1732783c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -32,7 +32,8 @@ "redux": "^3.6.0", "redux-logger": "^3.0.1", "redux-thunk": "^2.2.0", - "reselect": "^3.0.0" + "reselect": "^3.0.0", + "wavesurfer.js": "^2.0.0-beta01" }, "devDependencies": { "babel": "^6.5.2", -- 2.45.3