Merge branch 'master' into i18n
This commit is contained in:
commit
81afbf8d70
10 changed files with 62 additions and 35 deletions
28
README.md
28
README.md
|
@ -2,6 +2,8 @@
|
|||
|
||||
This is a graphical browser for the decentralized content marketplace provided by the [LBRY](https://lbry.io) protocol. It is essentially the [lbry daemon](https://github.com/lbryio/lbry) bundled with a UI using [Electron](http://electron.atom.io/).
|
||||
|
||||
![App Screenshot](https://lbry.io/img/lbry-ui.png)
|
||||
|
||||
## Installing
|
||||
|
||||
We provide installers for Windows, macOS, and Debian-based Linux.
|
||||
|
@ -18,26 +20,24 @@ To install from source or make changes to the application, continue reading belo
|
|||
|
||||
## Development
|
||||
|
||||
This repo uses submodules, so clone it using `--recursive`.
|
||||
### One-time Setup
|
||||
|
||||
### Setup
|
||||
1. Install node and npm.
|
||||
2. Check out this repo.
|
||||
3. Set up a Python virtual environment, or live on the wild side.
|
||||
4. Run `./build.sh`. This builds the UI assets and puts them into `app/dist`. It also downloads [lbry daemon](https://github.com/lbryio/lbry/releases).
|
||||
|
||||
The
|
||||
[lbry daemon](https://github.com/lbryio/lbry/blob/master/INSTALL.md) needs
|
||||
to be installed along with pyinstaller. You also need to be
|
||||
able to build the lbry-web-ui, so have node, webpack, etc installed.
|
||||
### Running
|
||||
|
||||
### Build
|
||||
Run `./node_modules/.bin/electron app`
|
||||
|
||||
run `./build.sh`
|
||||
### Ongoing Development
|
||||
1. `cd ui`
|
||||
2. `./watch.sh`
|
||||
|
||||
This builds the UI assets and puts them into `app/dist`. It also builds `app/dist/lbrynet-daemon`.
|
||||
This will set up a monitor that will automatically compile any changes to JS or CSS folders inside of the `ui` folder. This allows you to make changes and see them immediately by reloading the app.
|
||||
|
||||
### Run
|
||||
|
||||
`./node_modules/.bin/electron app`
|
||||
|
||||
### Package
|
||||
### Packaging
|
||||
|
||||
We use [electron-builder](https://github.com/electron-userland/electron-builder)
|
||||
to create distributable packages, which is run by calling:
|
||||
|
|
|
@ -52,6 +52,7 @@ export function doChangePath(path) {
|
|||
const state = getState()
|
||||
const pageTitle = selectPageTitle(state)
|
||||
window.document.title = pageTitle
|
||||
window.scrollTo(0, 0)
|
||||
|
||||
const currentPage = selectCurrentPage(state)
|
||||
if (currentPage === 'search') {
|
||||
|
|
|
@ -166,6 +166,8 @@ export function doDownloadFile(uri, streamInfo) {
|
|||
fileInfo,
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(doUpdateLoadStatus(uri, streamInfo.outpoint))
|
||||
})
|
||||
|
||||
lbryio.call('file', 'view', {
|
||||
|
@ -176,7 +178,6 @@ export function doDownloadFile(uri, streamInfo) {
|
|||
|
||||
rewards.claimEligiblePurchaseRewards()
|
||||
|
||||
dispatch(doUpdateLoadStatus(uri, streamInfo.outpoint))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ const makeSelect = () => {
|
|||
const selectIsAvailableForUri = makeSelectIsAvailableForUri()
|
||||
const selectDownloadingForUri = makeSelectDownloadingForUri()
|
||||
const selectCostInfoForUri = makeSelectCostInfoForUri()
|
||||
const selectLoadingForUri = makeSelectLoadingForUri()
|
||||
|
||||
const select = (state, props) => ({
|
||||
fileInfo: selectFileInfoForUri(state, props),
|
||||
|
@ -51,6 +52,7 @@ const makeSelect = () => {
|
|||
modal: selectCurrentModal(state),
|
||||
downloading: selectDownloadingForUri(state, props),
|
||||
costInfo: selectCostInfoForUri(state, props),
|
||||
loading: selectLoadingForUri(state, props),
|
||||
})
|
||||
|
||||
return select
|
||||
|
|
|
@ -63,6 +63,7 @@ class FileActions extends React.Component {
|
|||
closeModal,
|
||||
startDownload,
|
||||
costInfo,
|
||||
loading,
|
||||
} = this.props
|
||||
|
||||
const deleteChecked = this.state.deleteChecked,
|
||||
|
@ -73,7 +74,7 @@ class FileActions extends React.Component {
|
|||
|
||||
let content
|
||||
|
||||
if (downloading) {
|
||||
if (loading || downloading) {
|
||||
|
||||
const
|
||||
progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
|
||||
|
@ -110,7 +111,6 @@ class FileActions extends React.Component {
|
|||
content = <Link label={__("Open")} button="text" icon="icon-folder-open" onClick={() => openInShell(fileInfo)} />;
|
||||
} else {
|
||||
console.log('handle this case of file action props?');
|
||||
console.log(this.props)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -13,7 +13,8 @@ import {
|
|||
doLoadVideo,
|
||||
} from 'actions/content'
|
||||
import {
|
||||
makeSelectMetadataForUri
|
||||
makeSelectMetadataForUri,
|
||||
makeSelectContentTypeForUri,
|
||||
} from 'selectors/claims'
|
||||
import {
|
||||
makeSelectFileInfoForUri,
|
||||
|
@ -32,6 +33,7 @@ const makeSelect = () => {
|
|||
const selectIsLoading = makeSelectLoadingForUri()
|
||||
const selectIsDownloading = makeSelectDownloadingForUri()
|
||||
const selectMetadata = makeSelectMetadataForUri()
|
||||
const selectContentType = makeSelectContentTypeForUri()
|
||||
|
||||
const select = (state, props) => ({
|
||||
costInfo: selectCostInfo(state, props),
|
||||
|
@ -40,6 +42,7 @@ const makeSelect = () => {
|
|||
modal: selectCurrentModal(state),
|
||||
isLoading: selectIsLoading(state, props),
|
||||
isDownloading: selectIsDownloading(state, props),
|
||||
contentType: selectContentType(state, props),
|
||||
})
|
||||
|
||||
return select
|
||||
|
|
|
@ -2,6 +2,10 @@ import React from 'react';
|
|||
import FilePrice from 'component/filePrice'
|
||||
import Link from 'component/link';
|
||||
import Modal from 'component/modal';
|
||||
import lbry from 'lbry'
|
||||
import {
|
||||
Thumbnail,
|
||||
} from 'component/common'
|
||||
|
||||
class VideoPlayButton extends React.Component {
|
||||
onPurchaseConfirmed() {
|
||||
|
@ -33,6 +37,7 @@ class VideoPlayButton extends React.Component {
|
|||
isLoading,
|
||||
costInfo,
|
||||
fileInfo,
|
||||
mediaType,
|
||||
} = this.props
|
||||
|
||||
/*
|
||||
|
@ -44,13 +49,14 @@ class VideoPlayButton extends React.Component {
|
|||
*/
|
||||
|
||||
const disabled = isLoading || fileInfo === undefined || (fileInfo === null && (!costInfo || costInfo.cost === undefined))
|
||||
const icon = mediaType == "image" ? "icon-folder-o" : "icon-play"
|
||||
|
||||
return (<div>
|
||||
<Link button={ button ? button : null }
|
||||
disabled={disabled}
|
||||
label={label ? label : ""}
|
||||
className="video__play-button"
|
||||
icon="icon-play"
|
||||
icon={icon}
|
||||
onClick={this.onWatchClick.bind(this)} />
|
||||
<Modal contentLabel={__("Not enough credits")} isOpen={modal == 'notEnoughCredits'} onConfirmed={closeModal}>
|
||||
{__("You don't have enough LBRY credits to pay for this stream.")}
|
||||
|
@ -89,12 +95,14 @@ class Video extends React.Component {
|
|||
isLoading,
|
||||
isDownloading,
|
||||
fileInfo,
|
||||
contentType,
|
||||
} = this.props
|
||||
const {
|
||||
isPlaying = false,
|
||||
} = this.state
|
||||
|
||||
const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0
|
||||
const mediaType = lbry.getMediaType(contentType, fileInfo && fileInfo.file_name)
|
||||
|
||||
let loadStatusMessage = ''
|
||||
|
||||
|
@ -106,14 +114,24 @@ class Video extends React.Component {
|
|||
loadStatusMessage = __("Downloading stream... not long left now!")
|
||||
}
|
||||
|
||||
let klassName = ""
|
||||
if (isLoading || isDownloading) klassName += "video-embedded video"
|
||||
if (mediaType === "video") {
|
||||
klassName += "video-embedded video"
|
||||
klassName += isPlaying ? " video--active" : " video--hidden"
|
||||
} else {
|
||||
if (!isPlaying) klassName += "video-embedded"
|
||||
}
|
||||
const poster = metadata.thumbnail
|
||||
|
||||
return (
|
||||
<div className={"video " + this.props.className + (isPlaying ? " video--active" : " video--hidden")}>{
|
||||
isPlaying || isLoading ?
|
||||
<div className={klassName}>{
|
||||
isPlaying ?
|
||||
(!isReadyToPlay ?
|
||||
<span>{__("this is the world's worst loading screen and we shipped our software with it anyway...")} <br /><br />{loadStatusMessage}</span> :
|
||||
<VideoPlayer filename={fileInfo.file_name} poster={metadata.thumbnail} downloadPath={fileInfo.download_path} />) :
|
||||
<VideoPlayer filename={fileInfo.file_name} poster={poster} downloadPath={fileInfo.download_path} mediaType={mediaType} poster={poster} />) :
|
||||
<div className="video__cover" style={{backgroundImage: 'url("' + metadata.thumbnail + '")'}}>
|
||||
<VideoPlayButton startPlaying={this.startPlaying.bind(this)} {...this.props} />
|
||||
<VideoPlayButton startPlaying={this.startPlaying.bind(this)} {...this.props} mediaType={mediaType} />
|
||||
</div>
|
||||
}</div>
|
||||
);
|
||||
|
@ -126,10 +144,9 @@ const fs = require('fs')
|
|||
|
||||
class VideoPlayer extends React.Component {
|
||||
componentDidMount() {
|
||||
const elem = this.refs.video
|
||||
const elem = this.refs.media
|
||||
const {
|
||||
downloadPath,
|
||||
contentType,
|
||||
filename,
|
||||
} = this.props
|
||||
const file = {
|
||||
|
@ -138,7 +155,7 @@ class VideoPlayer extends React.Component {
|
|||
return fs.createReadStream(downloadPath, opts)
|
||||
}
|
||||
}
|
||||
player.render(file, elem, {
|
||||
player.append(file, elem, {
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
})
|
||||
|
@ -147,14 +164,15 @@ class VideoPlayer extends React.Component {
|
|||
render() {
|
||||
const {
|
||||
downloadPath,
|
||||
contentType,
|
||||
mediaType,
|
||||
poster,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<video controls ref="video" style={{backgroundImage: "url('" + poster + "')"}} >
|
||||
<source src={downloadPath} type={contentType} />
|
||||
</video>
|
||||
<div>
|
||||
{mediaType === "audio" && <Thumbnail src={poster} className="video-embedded" />}
|
||||
<div ref="media" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ lbry.imagePath = function(file)
|
|||
|
||||
lbry.getMediaType = function(contentType, fileName) {
|
||||
if (contentType) {
|
||||
return /^[^/]+/.exec(contentType);
|
||||
return /^[^/]+/.exec(contentType)[0];
|
||||
} else if (fileName) {
|
||||
var dotIndex = fileName.lastIndexOf('.');
|
||||
if (dotIndex == -1) {
|
||||
|
@ -319,7 +319,7 @@ lbry._balanceSubscribeInterval = 5000;
|
|||
|
||||
lbry._balanceUpdateInterval = null;
|
||||
lbry._updateBalanceSubscribers = function() {
|
||||
lbry.get_balance().then(function(balance) {
|
||||
lbry.wallet_balance().then(function(balance) {
|
||||
for (let callback of Object.values(lbry._balanceSubscribeCallbacks)) {
|
||||
callback(balance);
|
||||
}
|
||||
|
|
|
@ -95,11 +95,12 @@ lbryio.call = function(resource, action, params={}, method='get', evenIfDisabled
|
|||
};
|
||||
|
||||
lbryio.getAccessToken = () => {
|
||||
return getSession('accessToken');
|
||||
const token = getSession('accessToken');
|
||||
return token ? token.toString().trim() : token;
|
||||
}
|
||||
|
||||
lbryio.setAccessToken = (token) => {
|
||||
setSession('accessToken', token)
|
||||
setSession('accessToken', token ? token.toString().trim() : token)
|
||||
}
|
||||
|
||||
lbryio.authenticate = function() {
|
||||
|
|
|
@ -92,11 +92,12 @@ 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 = <UriIndicator uri={uri} />
|
||||
const mediaType = lbry.getMediaType(contentType)
|
||||
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<section className="show-page-media">
|
||||
{ contentType && contentType.startsWith('video/') ?
|
||||
{ ["video", "audio", "image"].indexOf(mediaType) !== -1 ?
|
||||
<Video className="video-embedded" uri={uri} /> :
|
||||
(metadata && metadata.thumbnail ? <Thumbnail src={metadata.thumbnail} /> : <Thumbnail />) }
|
||||
</section>
|
||||
|
|
Loading…
Reference in a new issue