diff --git a/ui/dist/index.html b/ui/dist/index.html
index b4239bc9a..8fbf0b5b6 100644
--- a/ui/dist/index.html
+++ b/ui/dist/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js
index d887fc318..fb24a0458 100644
--- a/ui/js/actions/content.js
+++ b/ui/js/actions/content.js
@@ -240,7 +240,11 @@ export function doLoadVideo() {
})
lbry.get({ uri }).then(streamInfo => {
- if (streamInfo === null || typeof streamInfo !== 'object') {
+ const timeout = streamInfo === null ||
+ typeof streamInfo !== 'object' ||
+ streamInfo.error == 'Timeout'
+
+ if(timeout) {
dispatch({
type: types.LOADING_VIDEO_FAILED,
data: { uri }
@@ -264,6 +268,12 @@ export function doWatchVideo() {
const alreadyDownloading = !!downloadingByUri[uri]
const { cost } = costInfo
+ // BUG if you delete a file from the file system system you're going to be
+ // asked to pay for it again. We need to check if the file is in the blobs
+ // here and then dispatch doLoadVideo() which will reconstruct it again from
+ // the blobs. Or perhaps there's another way to see if a file was already
+ // purchased?
+
// we already fully downloaded the file
if (fileInfo && fileInfo.completed) {
return Promise.resolve()
diff --git a/ui/js/component/channel-indicator.js b/ui/js/component/channel-indicator.js
deleted file mode 100644
index e19850c28..000000000
--- a/ui/js/component/channel-indicator.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import lbry from '../lbry.js';
-import lbryuri from '../lbryuri.js';
-import {Icon} from './common.js';
-
-const UriIndicator = React.createClass({
- propTypes: {
- uri: React.PropTypes.string.isRequired,
- hasSignature: React.PropTypes.bool.isRequired,
- signatureIsValid: React.PropTypes.bool,
- },
- render: function() {
-
- const uriObj = lbryuri.parse(this.props.uri);
-
- if (!this.props.hasSignature || !uriObj.isChannel) {
- return Anonymous ;
- }
-
- const channelUriObj = Object.assign({}, uriObj);
- delete channelUriObj.path;
- delete channelUriObj.contentName;
- const channelUri = lbryuri.build(channelUriObj, false);
-
- let icon, modifier;
- if (this.props.signatureIsValid) {
- modifier = 'valid';
- } else {
- icon = 'icon-times-circle';
- modifier = 'invalid';
- }
- return (
-
- {channelUri} {' '}
- { !this.props.signatureIsValid ?
- :
- '' }
-
- );
- }
-});
-
-export default UriIndicator;
\ No newline at end of file
diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx
index 5fe6a2dea..5d74949bc 100644
--- a/ui/js/component/fileActions/view.jsx
+++ b/ui/js/component/fileActions/view.jsx
@@ -116,188 +116,6 @@ class FileActionsRow extends React.Component {
}
}
-// const FileActionsRow = React.createClass({
-// _isMounted: false,
-// _fileInfoSubscribeId: null,
-
-// propTypes: {
-// uri: React.PropTypes.string,
-// outpoint: React.PropTypes.string.isRequired,
-// metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
-// contentType: React.PropTypes.string.isRequired,
-// },
-// getInitialState: function() {
-// return {
-// fileInfo: null,
-// modal: null,
-// menuOpen: false,
-// deleteChecked: false,
-// attemptingDownload: false,
-// attemptingRemove: false,
-// }
-// },
-// onFileInfoUpdate: function(fileInfo) {
-// if (this._isMounted) {
-// this.setState({
-// fileInfo: fileInfo ? fileInfo : false,
-// attemptingDownload: fileInfo ? false : this.state.attemptingDownload
-// });
-// }
-// },
-// tryDownload: function() {
-// this.setState({
-// attemptingDownload: true,
-// attemptingRemove: false
-// });
-// lbry.getCostInfo(this.props.uri).then(({cost}) => {
-// lbry.getBalance((balance) => {
-// if (cost > balance) {
-// this.setState({
-// modal: 'notEnoughCredits',
-// attemptingDownload: false,
-// });
-// } else if (this.state.affirmedPurchase) {
-// lbry.get({uri: this.props.uri}).then((streamInfo) => {
-// if (streamInfo === null || typeof streamInfo !== 'object') {
-// this.setState({
-// modal: 'timedOut',
-// attemptingDownload: false,
-// });
-// }
-// });
-// } else {
-// this.setState({
-// attemptingDownload: false,
-// modal: 'affirmPurchase'
-// })
-// }
-// });
-// });
-// },
-// closeModal: function() {
-// this.setState({
-// modal: null,
-// })
-// },
-// onDownloadClick: function() {
-// if (!this.state.fileInfo && !this.state.attemptingDownload) {
-// this.tryDownload();
-// }
-// },
-// onOpenClick: function() {
-// if (this.state.fileInfo && this.state.fileInfo.download_path) {
-// shell.openItem(this.state.fileInfo.download_path);
-// }
-// },
-// handleDeleteCheckboxClicked: function(event) {
-// this.setState({
-// deleteChecked: event.target.checked,
-// });
-// },
-// handleRevealClicked: function() {
-// if (this.state.fileInfo && this.state.fileInfo.download_path) {
-// shell.showItemInFolder(this.state.fileInfo.download_path);
-// }
-// },
-// handleRemoveClicked: function() {
-// this.setState({
-// modal: 'confirmRemove',
-// });
-// },
-// handleRemoveConfirmed: function() {
-// lbry.removeFile(this.props.outpoint, this.state.deleteChecked);
-// this.setState({
-// modal: null,
-// fileInfo: false,
-// attemptingDownload: false
-// });
-// },
-// onAffirmPurchase: function() {
-// this.setState({
-// affirmedPurchase: true,
-// modal: null
-// });
-// this.tryDownload();
-// },
-// openMenu: function() {
-// this.setState({
-// menuOpen: !this.state.menuOpen,
-// });
-// },
-// componentDidMount: function() {
-// this._isMounted = true;
-// this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
-// },
-// componentWillUnmount: function() {
-// this._isMounted = false;
-// if (this._fileInfoSubscribeId) {
-// lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
-// }
-// },
-// render: function() {
-// if (this.state.fileInfo === null)
-// {
-// return null;
-// }
-
-// const openInFolderMessage = window.navigator.platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder',
-// showMenu = !!this.state.fileInfo;
-
-// let linkBlock;
-// if (this.state.fileInfo === false && !this.state.attemptingDownload) {
-// linkBlock = ;
-// } else if (this.state.attemptingDownload || (!this.state.fileInfo.completed && !this.state.fileInfo.isMine)) {
-// const
-// progress = this.state.fileInfo ? this.state.fileInfo.written_bytes / this.state.fileInfo.total_bytes * 100 : 0,
-// label = this.state.fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...',
-// labelWithIcon = {label} ;
-
-// linkBlock = (
-//
-//
{labelWithIcon}
-// {labelWithIcon}
-//
-// );
-// } else {
-// linkBlock = ;
-// }
-
-// const uri = lbryuri.normalize(this.props.uri);
-// const title = this.props.metadata ? this.props.metadata.title : uri;
-// return (
-//
-// {this.state.fileInfo !== null || this.state.fileInfo.isMine
-// ? linkBlock
-// : null}
-// { showMenu ?
-//
-//
-//
-// : '' }
-//
-// Are you sure you'd like to buy {title} for credits?
-//
-//
-// You don't have enough LBRY credits to pay for this stream.
-//
-//
-// LBRY was unable to download the stream {uri} .
-//
-//
-// Are you sure you'd like to remove {title} from LBRY?
-
-// Delete this file from my computer
-//
-//
-// );
-// }
-// });
-
class FileActions extends React.Component {
constructor(props) {
super(props)
diff --git a/ui/js/component/fileCardStream/index.js b/ui/js/component/fileCardStream/index.js
index 14e3dc7f9..1a183846f 100644
--- a/ui/js/component/fileCardStream/index.js
+++ b/ui/js/component/fileCardStream/index.js
@@ -17,6 +17,9 @@ import {
import {
makeSelectFileInfoForUri,
} from 'selectors/file_info'
+import {
+ makeSelectResolvingUri,
+} from 'selectors/content'
import FileCardStream from './view'
const makeSelect = () => {
@@ -24,6 +27,8 @@ const makeSelect = () => {
const selectFileInfoForUri = makeSelectFileInfoForUri()
const selectMetadataForUri = makeSelectMetadataForUri()
const selectSourceForUri = makeSelectSourceForUri()
+ const selectResolvingUri = makeSelectResolvingUri()
+
const select = (state, props) => ({
claim: selectClaimForUri(state, props),
fileInfo: selectFileInfoForUri(state, props),
@@ -32,6 +37,7 @@ const makeSelect = () => {
hasSignature: false,
metadata: selectMetadataForUri(state, props),
source: selectSourceForUri(state, props),
+ isResolvingUri: selectResolvingUri(state, props),
})
return select
diff --git a/ui/js/component/fileCardStream/view.jsx b/ui/js/component/fileCardStream/view.jsx
index c3954d9b7..72284eb79 100644
--- a/ui/js/component/fileCardStream/view.jsx
+++ b/ui/js/component/fileCardStream/view.jsx
@@ -4,7 +4,7 @@ import lbryuri from 'lbryuri.js';
import Link from 'component/link';
import {Thumbnail, TruncatedText,} from 'component/common';
import FilePrice from 'component/filePrice'
-import UriIndicator from 'component/channel-indicator';
+import UriIndicator from 'component/uriIndicator';
class FileCardStream extends React.Component {
constructor(props) {
@@ -56,37 +56,43 @@ class FileCardStream extends React.Component {
return null;
}
- // if (!this.props.metadata) {
- // return null
- // }
+ const {
+ metadata,
+ isResolvingUri,
+ navigate,
+ hidePrice,
+ } = this.props
const uri = lbryuri.normalize(this.props.uri);
- const metadata = this.props.metadata;
const isConfirmed = !!metadata;
const title = isConfirmed ? metadata.title : uri;
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
const primaryUrl = 'show=' + uri;
+ let description = ""
+ if (isConfirmed) {
+ description = metadata.description
+ } else if (isResolvingUri) {
+ description = "Loading..."
+ } else {
+ description = This file is pending confirmation
+ }
+
return (
-
this.props.navigate(primaryUrl)} className="card__link">
+ navigate(primaryUrl)} className="card__link">
{title}
- { !this.props.hidePrice ? : null}
-
+ { !hidePrice ? : null}
+
{metadata &&
}
-
- {isConfirmed
- ? metadata.description
- : This file is pending confirmation. }
-
+ {description}
{this.state.showNsfwHelp && this.state.hovered
diff --git a/ui/js/component/fileTileStream/index.js b/ui/js/component/fileTileStream/index.js
index d212dfdae..80807f125 100644
--- a/ui/js/component/fileTileStream/index.js
+++ b/ui/js/component/fileTileStream/index.js
@@ -20,6 +20,9 @@ import {
import {
selectObscureNsfw,
} from 'selectors/app'
+import {
+ makeSelectResolvingUri,
+} from 'selectors/content'
import FileTileStream from './view'
const makeSelect = () => {
@@ -29,6 +32,7 @@ const makeSelect = () => {
const selectAvailabilityForUri = makeSelectAvailabilityForUri()
const selectMetadataForUri = makeSelectMetadataForUri()
const selectSourceForUri = makeSelectSourceForUri()
+ const selectResolvingUri = makeSelectResolvingUri()
const select = (state, props) => ({
claim: selectClaimForUri(state, props),
@@ -38,6 +42,7 @@ const makeSelect = () => {
obscureNsfw: selectObscureNsfw(state),
metadata: selectMetadataForUri(state, props),
source: selectSourceForUri(state, props),
+ isResolvingUri: selectResolvingUri(state, props),
})
return select
diff --git a/ui/js/component/fileTileStream/view.jsx b/ui/js/component/fileTileStream/view.jsx
index 2130df284..6a80772eb 100644
--- a/ui/js/component/fileTileStream/view.jsx
+++ b/ui/js/component/fileTileStream/view.jsx
@@ -5,7 +5,7 @@ import Link from 'component/link';
import FileActions from 'component/fileActions';
import {Thumbnail, TruncatedText,} from 'component/common.js';
import FilePrice from 'component/filePrice'
-import UriIndicator from 'component/channel-indicator.js';
+import UriIndicator from 'component/uriIndicator';
/*should be merged into FileTile once FileTile is refactored to take a single id*/
class FileTileStream extends React.Component {
@@ -63,7 +63,9 @@ class FileTileStream extends React.Component {
const {
metadata,
+ isResolvingUri,
navigate,
+ hidePrice,
} = this.props
const uri = lbryuri.normalize(this.props.uri);
@@ -71,6 +73,15 @@ class FileTileStream extends React.Component {
const title = isConfirmed ? metadata.title : uri;
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
+ let description = ""
+ if (isConfirmed) {
+ description = metadata.description
+ } else if (isResolvingUri) {
+ description = "Loading..."
+ } else {
+ description =
This file is pending confirmation
+ }
+
return (
@@ -101,11 +112,7 @@ class FileTileStream extends React.Component {
-
- {isConfirmed
- ? metadata.description
- : This file is pending confirmation. }
-
+ {description}
diff --git a/ui/js/component/reward-link.js b/ui/js/component/reward-link.js
index d003e0303..b6ae09fed 100644
--- a/ui/js/component/reward-link.js
+++ b/ui/js/component/reward-link.js
@@ -1,7 +1,9 @@
import React from 'react';
-import {Icon} from './common.js';
-import Modal from '../component/modal.js';
-import rewards from '../rewards.js';
+import lbry from 'lbry'
+import {Icon} from 'component/common';
+import Modal from 'component/modal';
+import rewards from 'rewards';
+import Link from 'component/link'
export let RewardLink = React.createClass({
propTypes: {
diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx
index 7fa7df107..cb57dc4a8 100644
--- a/ui/js/component/router/view.jsx
+++ b/ui/js/component/router/view.jsx
@@ -6,7 +6,7 @@ import ReportPage from 'page/report.js';
import StartPage from 'page/start.js';
import WalletPage from 'page/wallet';
import ShowPage from 'page/showPage';
-import PublishPage from 'page/publish.js';
+import PublishPage from 'page/publish';
import DiscoverPage from 'page/discover';
import SplashScreen from 'component/splash.js';
import RewardsPage from 'page/rewards.js';
diff --git a/ui/js/component/uriIndicator/index.js b/ui/js/component/uriIndicator/index.js
new file mode 100644
index 000000000..6cadf91b3
--- /dev/null
+++ b/ui/js/component/uriIndicator/index.js
@@ -0,0 +1,20 @@
+import React from 'react'
+import {
+ connect,
+} from 'react-redux'
+import {
+ makeSelectClaimForUri,
+} from 'selectors/claims'
+import UriIndicator from './view'
+
+const makeSelect = () => {
+ const selectClaimForUri = makeSelectClaimForUri()
+
+ const select = (state, props) => ({
+ claim: selectClaimForUri(state, props),
+ })
+
+ return select
+}
+
+export default connect(makeSelect, null)(UriIndicator)
diff --git a/ui/js/component/uriIndicator/view.jsx b/ui/js/component/uriIndicator/view.jsx
new file mode 100644
index 000000000..cc3d4f0eb
--- /dev/null
+++ b/ui/js/component/uriIndicator/view.jsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import lbry from 'lbry';
+import lbryuri from 'lbryuri';
+import {Icon} from 'component/common';
+
+const UriIndicator = (props) => {
+ const {
+ uri,
+ claim: {
+ has_signature: hasSignature,
+ signature_is_valid: signatureIsValid,
+ } = {},
+ } = props
+
+ const uriObj = lbryuri.parse(uri);
+
+ if (!hasSignature || !uriObj.isChannel) {
+ return Anonymous ;
+ }
+
+ const channelUriObj = Object.assign({}, uriObj);
+ delete channelUriObj.path;
+ delete channelUriObj.contentName;
+ const channelUri = lbryuri.build(channelUriObj, false);
+
+ let icon, modifier;
+ if (signatureIsValid) {
+ modifier = 'valid';
+ } else {
+ icon = 'icon-times-circle';
+ modifier = 'invalid';
+ }
+
+ return (
+
+ {channelUri} {' '}
+ { !signatureIsValid ?
+ :
+ '' }
+
+ )
+}
+
+export default UriIndicator;
\ No newline at end of file
diff --git a/ui/js/page/discover/view.jsx b/ui/js/page/discover/view.jsx
index 618ef675c..7bca2f55f 100644
--- a/ui/js/page/discover/view.jsx
+++ b/ui/js/page/discover/view.jsx
@@ -84,7 +84,7 @@ const FeaturedCategory = (props) => {
{category &&
}
- {names && names.map(name => )}
+ {names && names.map(name => )}
)
}
diff --git a/ui/js/page/publish/index.js b/ui/js/page/publish/index.js
new file mode 100644
index 000000000..29347b6ed
--- /dev/null
+++ b/ui/js/page/publish/index.js
@@ -0,0 +1,17 @@
+import React from 'react'
+import {
+ connect,
+} from 'react-redux'
+import {
+ doNavigate,
+} from 'actions/app'
+import PublishPage from './view'
+
+const select = (state) => ({
+})
+
+const perform = (dispatch) => ({
+ navigate: (path) => dispatch(doNavigate(path)),
+})
+
+export default connect(select, perform)(PublishPage)
diff --git a/ui/js/page/publish.js b/ui/js/page/publish/view.jsx
similarity index 98%
rename from ui/js/page/publish.js
rename to ui/js/page/publish/view.jsx
index ad600f19d..24a311853 100644
--- a/ui/js/page/publish.js
+++ b/ui/js/page/publish/view.jsx
@@ -1,10 +1,10 @@
import React from 'react';
-import lbry from '../lbry.js';
-import {FormField, FormRow} from '../component/form.js';
-import Link from '../component/link';
-import rewards from '../rewards.js';
-import lbryio from '../lbryio.js';
-import Modal from '../component/modal.js';
+import lbry from 'lbry';
+import {FormField, FormRow} from 'component/form.js';
+import Link from 'component/link';
+import rewards from 'rewards';
+import lbryio from 'lbryio';
+import Modal from 'component/modal';
var PublishPage = React.createClass({
_requiredFields: ['meta_title', 'name', 'bid', 'tos_agree'],
@@ -148,7 +148,7 @@ var PublishPage = React.createClass({
});
},
handlePublishStartedConfirmed: function() {
- window.location = "?published";
+ this.props.navigate('published')
},
handlePublishError: function(error) {
this.setState({
diff --git a/ui/js/page/rewards.js b/ui/js/page/rewards.js
index 5bb55f9ff..2fd58db3a 100644
--- a/ui/js/page/rewards.js
+++ b/ui/js/page/rewards.js
@@ -1,10 +1,10 @@
import React from 'react';
-import lbry from '../lbry.js';
-import lbryio from '../lbryio.js';
-import {CreditAmount, Icon} from '../component/common.js';
-import rewards from '../rewards.js';
-import Modal from '../component/modal.js';
-import {RewardLink} from '../component/reward-link.js';
+import lbry from 'lbry';
+import lbryio from 'lbryio';
+import {CreditAmount, Icon} from 'component/common.js';
+import rewards from 'rewards';
+import Modal from 'component/modal';
+import {RewardLink} from 'component/reward-link';
const RewardTile = React.createClass({
propTypes: {
diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx
index 9620d2c74..be6c28785 100644
--- a/ui/js/page/showPage/view.jsx
+++ b/ui/js/page/showPage/view.jsx
@@ -11,7 +11,7 @@ import {
import FilePrice from 'component/filePrice'
import FileActions from 'component/fileActions';
import Link from 'component/link';
-import UriIndicator from 'component/channel-indicator.js';
+import UriIndicator from 'component/uriIndicator';
const FormatItem = (props) => {
const {
@@ -105,7 +105,7 @@ const ShowPage = (props) => {
{ uriLookupComplete ?
-
+
diff --git a/ui/js/page/video/view.jsx b/ui/js/page/video/view.jsx
index c71307119..2669cffe5 100644
--- a/ui/js/page/video/view.jsx
+++ b/ui/js/page/video/view.jsx
@@ -11,8 +11,7 @@ import lbryio from 'lbryio';
import rewards from 'rewards';
import LoadScreen from 'component/load_screen'
-const fs = require('fs');
-const VideoStream = require('videostream');
+const plyr = require('plyr')
class WatchLink extends React.Component {
confirmPurchaseClick() {
@@ -164,18 +163,22 @@ class VideoPlayer extends React.PureComponent {
const elem = this.refs.video
const {
downloadPath,
+ contentType,
} = this.props
- const mediaFile = {
- createReadStream: (opts) =>
- fs.createReadStream(downloadPath, opts)
- }
- const videostream = VideoStream(mediaFile, elem)
- elem.play()
+ const players = plyr.setup(elem)
+ players[0].play()
}
render() {
+ const {
+ downloadPath,
+ contentType,
+ } = this.props
+
return (
-
+
+
+
)
}
}
diff --git a/ui/js/reducers/app.js b/ui/js/reducers/app.js
index 13b1bb6b9..380c0f2c9 100644
--- a/ui/js/reducers/app.js
+++ b/ui/js/reducers/app.js
@@ -16,6 +16,12 @@ const defaultState = {
hasSignature: false,
}
+reducers[types.DAEMON_READY] = function(state, action) {
+ return Object.assign({}, state, {
+ daemonReady: true,
+ })
+}
+
reducers[types.NAVIGATE] = function(state, action) {
return Object.assign({}, state, {
currentPath: action.data.path,
diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js
index a269e98f2..e0d1a7a43 100644
--- a/ui/js/selectors/app.js
+++ b/ui/js/selectors/app.js
@@ -39,8 +39,7 @@ export const selectPageTitle = createSelector(
case 'wallet':
case 'send':
case 'receive':
- case 'claim':
- case 'referral':
+ case 'rewards':
return 'Wallet'
case 'downloaded':
return 'My Files'
@@ -129,14 +128,12 @@ export const selectHeaderLinks = createSelector(
case 'wallet':
case 'send':
case 'receive':
- case 'claim':
- case 'referral':
+ case 'rewards':
return {
'wallet' : 'Overview',
'send' : 'Send',
'receive' : 'Receive',
- 'claim' : 'Claim Beta Code',
- 'referral' : 'Check Referral Credit',
+ 'rewards': 'Rewards',
};
case 'downloaded':
case 'published':
diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js
index be38c21b3..87b91182d 100644
--- a/ui/js/selectors/content.js
+++ b/ui/js/selectors/content.js
@@ -96,3 +96,19 @@ export const shouldFetchPublishedContent = createSelector(
return true
}
)
+
+export const selectResolvingUris = createSelector(
+ _selectState,
+ (state) => state.resolvingUris || []
+)
+
+const selectResolvingUri = (state, props) => {
+ return selectResolvingUris(state).indexOf(props.uri) != -1
+}
+
+export const makeSelectResolvingUri = () => {
+ return createSelector(
+ selectResolvingUri,
+ (resolving) => resolving
+ )
+}
diff --git a/ui/package.json b/ui/package.json
index 8f7e754e1..ee8db2a1a 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -26,6 +26,7 @@
"intersection-observer": "^0.2.1",
"mediaelement": "^2.23.4",
"node-sass": "^3.8.0",
+ "plyr": "^2.0.12",
"rc-progress": "^2.0.6",
"react": "^15.4.0",
"react-dom": "^15.4.0",
@@ -34,8 +35,7 @@
"redux": "^3.6.0",
"redux-logger": "^3.0.1",
"redux-thunk": "^2.2.0",
- "reselect": "^3.0.0",
- "videostream": "^2.4.2"
+ "reselect": "^3.0.0"
},
"devDependencies": {
"babel": "^6.5.2",