Channels, round 3 #35
11 changed files with 148 additions and 170 deletions
|
@ -10,7 +10,7 @@ import StartPage from './page/start.js';
|
|||
import ClaimCodePage from './page/claim_code.js';
|
||||
import ReferralPage from './page/referral.js';
|
||||
import WalletPage from './page/wallet.js';
|
||||
import DetailPage from './page/show.js';
|
||||
import ShowPage from './page/show.js';
|
||||
import PublishPage from './page/publish.js';
|
||||
import DiscoverPage from './page/discover.js';
|
||||
import SplashScreen from './component/splash.js';
|
||||
|
@ -259,7 +259,7 @@ var App = React.createClass({
|
|||
case 'help':
|
||||
return <HelpPage />;
|
||||
case 'watch':
|
||||
return <WatchPage name={this.state.pageArgs} />;
|
||||
return <WatchPage uri={this.state.pageArgs} />;
|
||||
case 'report':
|
||||
return <ReportPage />;
|
||||
case 'downloaded':
|
||||
|
@ -277,7 +277,7 @@ var App = React.createClass({
|
|||
case 'receive':
|
||||
return <WalletPage viewingPage={this.state.viewingPage} />;
|
||||
case 'show':
|
||||
return <DetailPage name={this.state.pageArgs} />;
|
||||
return <ShowPage uri={this.state.pageArgs} />;
|
||||
case 'publish':
|
||||
return <PublishPage />;
|
||||
case 'developer':
|
||||
|
|
|
@ -6,11 +6,11 @@ import {Icon} from './common.js';
|
|||
const ChannelIndicator = React.createClass({
|
||||
propTypes: {
|
||||
uri: React.PropTypes.string.isRequired,
|
||||
claimInfo: React.PropTypes.object.isRequired,
|
||||
hasSignature: React.PropTypes.bool.isRequired,
|
||||
signatureIsValid: React.PropTypes.bool,
|
||||
},
|
||||
render: function() {
|
||||
const {name, has_signature, signature_is_valid} = this.props.claimInfo;
|
||||
if (!has_signature) {
|
||||
if (!this.props.hasSignature) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ const ChannelIndicator = React.createClass({
|
|||
const channelUri = uri.buildLbryUri(channelUriObj, false);
|
||||
|
||||
let icon, modifier;
|
||||
if (!signature_is_valid) {
|
||||
if (this.props.signatureIsValid) {
|
||||
icon = 'icon-check-circle';
|
||||
modifier = 'valid';
|
||||
} else {
|
||||
|
|
|
@ -11,11 +11,11 @@ const {shell} = require('electron');
|
|||
|
||||
let WatchLink = React.createClass({
|
||||
propTypes: {
|
||||
streamName: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
downloadStarted: React.PropTypes.bool,
|
||||
},
|
||||
startVideo: function() {
|
||||
window.location = '?watch=' + this.props.streamName;
|
||||
window.location = '?watch=' + this.props.uri;
|
||||
},
|
||||
handleClick: function() {
|
||||
this.setState({
|
||||
|
@ -25,7 +25,7 @@ let WatchLink = React.createClass({
|
|||
if (this.props.downloadStarted) {
|
||||
this.startVideo();
|
||||
} else {
|
||||
lbry.getCostInfoForName(this.props.streamName, ({cost}) => {
|
||||
lbry.getCostInfo(this.props.uri, ({cost}) => {
|
||||
lbry.getBalance((balance) => {
|
||||
if (cost > balance) {
|
||||
this.setState({
|
||||
|
@ -67,10 +67,10 @@ let FileActionsRow = React.createClass({
|
|||
_fileInfoSubscribeId: null,
|
||||
|
||||
propTypes: {
|
||||
streamName: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
outpoint: React.PropTypes.string.isRequired,
|
||||
metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
|
||||
contentType: React.PropTypes.string,
|
||||
contentType: React.PropTypes.string.isRequired,
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
|
@ -95,7 +95,7 @@ let FileActionsRow = React.createClass({
|
|||
attemptingDownload: true,
|
||||
attemptingRemove: false
|
||||
});
|
||||
lbry.getCostInfoForName(this.props.streamName, ({cost}) => {
|
||||
lbry.getCostInfo(this.props.uri, ({cost}) => {
|
||||
lbry.getBalance((balance) => {
|
||||
if (cost > balance) {
|
||||
this.setState({
|
||||
|
@ -103,7 +103,7 @@ let FileActionsRow = React.createClass({
|
|||
attemptingDownload: false,
|
||||
});
|
||||
} else {
|
||||
lbry.getStream(this.props.streamName, (streamInfo) => {
|
||||
lbry.get({uri: this.props.uri}).then((streamInfo) => {
|
||||
if (streamInfo === null || typeof streamInfo !== 'object') {
|
||||
this.setState({
|
||||
modal: 'timedOut',
|
||||
|
@ -199,7 +199,7 @@ let FileActionsRow = React.createClass({
|
|||
return (
|
||||
<div>
|
||||
{this.props.contentType && this.props.contentType.startsWith('video/')
|
||||
? <WatchLink streamName={this.props.streamName} downloadStarted={!!this.state.fileInfo} />
|
||||
? <WatchLink uri={this.props.uri} downloadStarted={!!this.state.fileInfo} />
|
||||
: null}
|
||||
{this.state.fileInfo !== null || this.state.fileInfo.isMine
|
||||
? linkBlock
|
||||
|
@ -215,7 +215,7 @@ let FileActionsRow = React.createClass({
|
|||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'timedOut'} contentLabel="Download failed"
|
||||
onConfirmed={this.closeModal}>
|
||||
LBRY was unable to download the stream <strong>lbry://{this.props.streamName}</strong>.
|
||||
LBRY was unable to download the stream <strong>lbry://{this.props.uri}</strong>.
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'confirmRemove'} contentLabel="Not enough credits"
|
||||
type="confirm" confirmButtonLabel="Remove" onConfirmed={this.handleRemoveConfirmed}
|
||||
|
@ -234,7 +234,7 @@ export let FileActions = React.createClass({
|
|||
_fileInfoSubscribeId: null,
|
||||
|
||||
propTypes: {
|
||||
streamName: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
outpoint: React.PropTypes.string.isRequired,
|
||||
metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
|
||||
contentType: React.PropTypes.string,
|
||||
|
@ -262,6 +262,7 @@ export let FileActions = React.createClass({
|
|||
this._isMounted = true;
|
||||
this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
|
||||
lbry.getStreamAvailability(this.props.uri, (availability) => {
|
||||
lbry.get_availability({uri: this.props.uri}, (availability) => {
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
available: availability > 0,
|
||||
|
@ -291,7 +292,7 @@ export let FileActions = React.createClass({
|
|||
return (<section className="file-actions">
|
||||
{
|
||||
fileInfo || this.state.available || this.state.forceShowActions
|
||||
? <FileActionsRow outpoint={this.props.outpoint} metadata={this.props.metadata} streamName={this.props.streamName}
|
||||
? <FileActionsRow outpoint={this.props.outpoint} metadata={this.props.metadata} uri={this.props.uri}
|
||||
contentType={this.props.contentType} />
|
||||
: <div>
|
||||
<div className="button-set-item empty">This file is not currently available.</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import uri from '../uri.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import {FileActions} from '../component/file-actions.js';
|
||||
import {Thumbnail, TruncatedText, CreditAmount} from '../component/common.js';
|
||||
|
@ -22,14 +23,15 @@ let FilePrice = React.createClass({
|
|||
componentDidMount: function() {
|
||||
this._isMounted = true;
|
||||
|
||||
lbry.getCostInfoForName(this.props.uri, ({cost, includesData}) => {
|
||||
lbry.getCostInfo(this.props.uri, ({cost, includesData}) => {
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
cost: cost,
|
||||
costIncludesData: includesData,
|
||||
});
|
||||
}
|
||||
}, () => {
|
||||
}, (err) => {
|
||||
console.log('error from getCostInfo callback:', err)
|
||||
// If we get an error looking up cost information, do nothing
|
||||
});
|
||||
},
|
||||
|
@ -56,12 +58,14 @@ let FilePrice = React.createClass({
|
|||
export let FileTileStream = React.createClass({
|
||||
_fileInfoSubscribeId: null,
|
||||
_isMounted: null,
|
||||
_metadata: null,
|
||||
|
||||
propTypes: {
|
||||
uri: React.PropTypes.string,
|
||||
claimInfo: React.PropTypes.object,
|
||||
metadata: React.PropTypes.object.isRequired,
|
||||
contentType: React.PropTypes.string.isRequired,
|
||||
outpoint: React.PropTypes.string,
|
||||
hasSignature: React.PropTypes.bool,
|
||||
signatureIsValid: React.PropTypes.bool,
|
||||
hideOnRemove: React.PropTypes.bool,
|
||||
hidePrice: React.PropTypes.bool,
|
||||
obscureNsfw: React.PropTypes.bool
|
||||
|
@ -76,14 +80,10 @@ export let FileTileStream = React.createClass({
|
|||
getDefaultProps: function() {
|
||||
return {
|
||||
obscureNsfw: !lbry.getClientSetting('showNsfw'),
|
||||
hidePrice: false
|
||||
hidePrice: false,
|
||||
hasSignature: false,
|
||||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
const {value: {stream: {metadata, source: {contentType}}}} = this.props.claimInfo;
|
||||
this._metadata = metadata;
|
||||
this._contentType = contentType;
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this._isMounted = true;
|
||||
if (this.props.hideOnRemove) {
|
||||
|
@ -103,7 +103,7 @@ export let FileTileStream = React.createClass({
|
|||
}
|
||||
},
|
||||
handleMouseOver: function() {
|
||||
if (this.props.obscureNsfw && this.props.metadata && this._metadata.nsfw) {
|
||||
if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) {
|
||||
this.setState({
|
||||
showNsfwHelp: true,
|
||||
});
|
||||
|
@ -117,25 +117,30 @@ export let FileTileStream = React.createClass({
|
|||
}
|
||||
},
|
||||
render: function() {
|
||||
console.log('rendering.')
|
||||
if (this.state.isHidden) {
|
||||
console.log('hidden, so returning null')
|
||||
return null;
|
||||
}
|
||||
|
||||
const metadata = this._metadata;
|
||||
console.log("inside FileTileStream. metadata is", this.props.metadata)
|
||||
|
||||
const lbryUri = uri.normalizeLbryUri(this.props.uri);
|
||||
const metadata = this.props.metadata;
|
||||
const isConfirmed = typeof metadata == 'object';
|
||||
const title = isConfirmed ? metadata.title : ('lbry://' + this.props.uri);
|
||||
const title = isConfirmed ? metadata.title : lbryUri;
|
||||
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
|
||||
return (
|
||||
<section className={ 'file-tile card ' + (obscureNsfw ? 'card-obscured ' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
|
||||
<div className={"row-fluid card-content file-tile__row"}>
|
||||
<div className="span3">
|
||||
<a href={'?show=' + this.props.uri}><Thumbnail className="file-tile__thumbnail" src={metadata.thumbnail} alt={'Photo for ' + (title || this.props.uri)} /></a>
|
||||
<a href={'?show=' + lbryUri}><Thumbnail className="file-tile__thumbnail" src={metadata.thumbnail} alt={'Photo for ' + (title || this.props.uri)} /></a>
|
||||
</div>
|
||||
<div className="span9">
|
||||
{ !this.props.hidePrice
|
||||
? <FilePrice uri={this.props.uri} />
|
||||
: null}
|
||||
<div className="meta"><a href={'?show=' + this.props.uri}>{'lbry://' + this.props.uri}</a></div>
|
||||
<div className="meta"><a href={'?show=' + this.props.uri}>{lbryUri}</a></div>
|
||||
<h3 className="file-tile__title">
|
||||
<a href={'?show=' + this.props.uri}>
|
||||
<TruncatedText lines={1}>
|
||||
|
@ -143,8 +148,9 @@ export let FileTileStream = React.createClass({
|
|||
</TruncatedText>
|
||||
</a>
|
||||
</h3>
|
||||
<ChannelIndicator uri={this.props.uri} claimInfo={this.props.claimInfo} />
|
||||
<FileActions uri={this.props.uri} outpoint={this.props.outpoint} metadata={metadata} contentType={this._contentType} />
|
||||
<ChannelIndicator uri={lbryUri} metadata={metadata} contentType={this.props.contentType}
|
||||
hasSignature={this.props.hasSignature} signatureIsValid={this.props.signatureIsValid} />
|
||||
<FileActions uri={this.props.uri} outpoint={this.props.outpoint} metadata={metadata} contentType={this.props.contentType} />
|
||||
<p className="file-tile__description">
|
||||
<TruncatedText lines={3}>
|
||||
{isConfirmed
|
||||
|
@ -186,11 +192,9 @@ export let FileTile = React.createClass({
|
|||
this._isMounted = true;
|
||||
|
||||
lbry.resolve({uri: this.props.uri}).then(({claim: claimInfo}) => {
|
||||
const {value: {stream: {metadata}}, txid, nout} = claimInfo;
|
||||
if (this._isMounted && claimInfo.value.stream.metadata) {
|
||||
// In case of a failed lookup, metadata will be null, in which case the component will never display
|
||||
this.setState({
|
||||
outpoint: txid + ':' + nout,
|
||||
claimInfo: claimInfo,
|
||||
});
|
||||
}
|
||||
|
@ -200,11 +204,13 @@ export let FileTile = React.createClass({
|
|||
this._isMounted = false;
|
||||
},
|
||||
render: function() {
|
||||
if (!this.state.claimInfo || !this.state.outpoint) {
|
||||
if (!this.state.claimInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <FileTileStream outpoint={this.state.outpoint} claimInfo={this.state.claimInfo}
|
||||
{... this.props} uri={this.props.uri}/>;
|
||||
const {txid, nout, has_signature, signature_is_valid,
|
||||
value: {stream: {metadata, source: {contentType}}}} = this.state.claimInfo;
|
||||
return <FileTileStream outpoint={txid + ':' + nout} metadata={metadata} contentType={contentType}
|
||||
hasSignature={has_signature} signatureIsValid={signature_is_valid} {... this.props} />;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import lighthouse from './lighthouse.js';
|
||||
import jsonrpc from './jsonrpc.js';
|
||||
import uri from './uri.js';
|
||||
import {getLocal, setLocal} from './utils.js';
|
||||
|
||||
const {remote} = require('electron');
|
||||
|
@ -219,23 +220,6 @@ lbry.getMyClaim = function(name, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
lbry.getKeyFee = function(name, callback, errorCallback) {
|
||||
if (!name) {
|
||||
throw new Error(`Name required.`);
|
||||
}
|
||||
lbry.call('stream_cost_estimate', { name: name }, callback, errorCallback);
|
||||
}
|
||||
|
||||
lbry.getTotalCost = function(name, size, callback, errorCallback) {
|
||||
if (!name) {
|
||||
throw new Error(`Name required.`);
|
||||
}
|
||||
lbry.call('stream_cost_estimate', {
|
||||
name: name,
|
||||
size: size,
|
||||
}, callback, errorCallback);
|
||||
}
|
||||
|
||||
lbry.getPeersForBlobHash = function(blobHash, callback) {
|
||||
let timedOut = false;
|
||||
const timeout = setTimeout(() => {
|
||||
|
@ -251,16 +235,9 @@ lbry.getPeersForBlobHash = function(blobHash, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
lbry.getStreamAvailability = function(name, callback, errorCallback) {
|
||||
if (!name) {
|
||||
throw new Error(`Name required.`);
|
||||
}
|
||||
lbry.call('get_availability', {name: name}, callback, errorCallback);
|
||||
}
|
||||
|
||||
lbry.getCostInfoForName = function(name, callback, errorCallback) {
|
||||
lbry.getCostInfo = function(lbryUri, callback, errorCallback) {
|
||||
/**
|
||||
* Takes a LBRY name; will first try and calculate a total cost using
|
||||
* Takes a LBRY URI; will first try and calculate a total cost using
|
||||
* Lighthouse. If Lighthouse can't be reached, it just retrives the
|
||||
* key fee.
|
||||
*
|
||||
|
@ -274,7 +251,7 @@ lbry.getCostInfoForName = function(name, callback, errorCallback) {
|
|||
}
|
||||
|
||||
function getCostWithData(name, size, callback, errorCallback) {
|
||||
lbry.getTotalCost(name, size, (cost) => {
|
||||
lbry.stream_cost_estimate({name, size}).then((cost) => {
|
||||
callback({
|
||||
cost: cost,
|
||||
includesData: true,
|
||||
|
@ -283,7 +260,7 @@ lbry.getCostInfoForName = function(name, callback, errorCallback) {
|
|||
}
|
||||
|
||||
function getCostNoData(name, callback, errorCallback) {
|
||||
lbry.getKeyFee(name, (cost) => {
|
||||
lbry.stream_cost_estimate({name}).then((cost) => {
|
||||
callback({
|
||||
cost: cost,
|
||||
includesData: false,
|
||||
|
@ -291,6 +268,9 @@ lbry.getCostInfoForName = function(name, callback, errorCallback) {
|
|||
}, errorCallback);
|
||||
}
|
||||
|
||||
const uriObj = uri.parseLbryUri(lbryUri);
|
||||
const name = uriObj.path || uriObj.name;
|
||||
|
||||
lighthouse.get_size_for_name(name).then((size) => {
|
||||
getCostWithData(name, size, callback, errorCallback);
|
||||
}, () => {
|
||||
|
@ -325,14 +305,6 @@ lbry.getMyClaims = function(callback) {
|
|||
lbry.call('get_name_claims', {}, callback);
|
||||
}
|
||||
|
||||
lbry.startFile = function(name, callback) {
|
||||
lbry.call('start_lbry_file', { name: name }, callback);
|
||||
}
|
||||
|
||||
lbry.stopFile = function(name, callback) {
|
||||
lbry.call('stop_lbry_file', { name: name }, callback);
|
||||
}
|
||||
|
||||
lbry.removeFile = function(outpoint, deleteTargetFile=true, callback) {
|
||||
this._removedFiles.push(outpoint);
|
||||
this._updateFileInfoSubscribers(outpoint);
|
||||
|
|
|
@ -84,7 +84,7 @@ var FeaturedContent = React.createClass({
|
|||
<div className="row-fluid">
|
||||
<div className="span6">
|
||||
<h3>Featured Content</h3>
|
||||
{ this.state.featuredNames.map((name) => { return <FileTile key={name} uri={name} /> }) }
|
||||
{ this.state.featuredNames.map(name => <FileTile key={name} uri={name} />) }
|
||||
</div>
|
||||
<div className="span6">
|
||||
<h3>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import uri from '../uri.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import FormField from '../component/form.js';
|
||||
import {FileTileStream} from '../component/file-tile.js';
|
||||
|
@ -160,14 +161,14 @@ export let FileList = React.createClass({
|
|||
seenUris = {};
|
||||
|
||||
const fileInfosSorted = this._sortFunctions[this.state.sortBy](this.props.fileInfos);
|
||||
for (let {name, outpoint, metadata} of fileInfosSorted) {
|
||||
for (let {name, outpoint, metadata: {stream: {metadata}}, mime_type, claim_id} of fileInfosSorted) {
|
||||
if (!metadata || seenUris[name]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seenUris[name] = true;
|
||||
content.push(<FileTileStream key={outpoint} outpoint={outpoint} name={name} hideOnRemove={true}
|
||||
hidePrice={this.props.hidePrices} metadata={metadata} />);
|
||||
content.push(<FileTileStream key={outpoint} outpoint={outpoint} uri={uri.buildLbryUri({name, claimId: claim_id})} hideOnRemove={true}
|
||||
hidePrice={this.props.hidePrices} metadata={metadata} contentType={mime_type} />);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import uri from '../uri.js';
|
||||
import FormField from '../component/form.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import Modal from '../component/modal.js';
|
||||
|
@ -169,49 +170,45 @@ var PublishPage = React.createClass({
|
|||
rawName: rawName,
|
||||
});
|
||||
|
||||
var name = rawName.toLowerCase();
|
||||
|
||||
lbry.resolveName(name, (info) => {
|
||||
const name = rawName.toLowerCase();
|
||||
lbry.resolve({uri: name}).then((info) => {
|
||||
if (name != this.refs.name.getValue().toLowerCase()) {
|
||||
// A new name has been typed already, so bail
|
||||
return;
|
||||
}
|
||||
lbry.getMyClaim(name, (myClaimInfo) => {
|
||||
lbry.getClaimInfo(name, (claimInfo) => {
|
||||
if (name != this.refs.name.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info) {
|
||||
this.setState({
|
||||
name: name,
|
||||
nameResolved: false,
|
||||
myClaimExists: false,
|
||||
const topClaimIsMine = (myClaimInfo && myClaimInfo.amount >= claimInfo.amount);
|
||||
const newState = {
|
||||
name: name,
|
||||
nameResolved: true,
|
||||
topClaimValue: parseFloat(claimInfo.amount),
|
||||
myClaimExists: !!myClaimInfo,
|
||||
myClaimValue: myClaimInfo ? parseFloat(myClaimInfo.amount) : null,
|
||||
myClaimMetadata: myClaimInfo ? myClaimInfo.value : null,
|
||||
topClaimIsMine: topClaimIsMine,
|
||||
};
|
||||
|
||||
if (topClaimIsMine) {
|
||||
newState.bid = myClaimInfo.amount;
|
||||
} else if (this.state.myClaimMetadata) {
|
||||
// Just changed away from a name we have a claim on, so clear pre-fill
|
||||
newState.bid = '';
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
});
|
||||
} else {
|
||||
lbry.getMyClaim(name, (myClaimInfo) => {
|
||||
lbry.getClaimInfo(name, (claimInfo) => {
|
||||
if (name != this.refs.name.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const topClaimIsMine = (myClaimInfo && myClaimInfo.amount >= claimInfo.amount);
|
||||
const newState = {
|
||||
name: name,
|
||||
nameResolved: true,
|
||||
topClaimValue: parseFloat(claimInfo.amount),
|
||||
myClaimExists: !!myClaimInfo,
|
||||
myClaimValue: myClaimInfo ? parseFloat(myClaimInfo.amount) : null,
|
||||
myClaimMetadata: myClaimInfo ? myClaimInfo.value : null,
|
||||
topClaimIsMine: topClaimIsMine,
|
||||
};
|
||||
|
||||
if (topClaimIsMine) {
|
||||
newState.bid = myClaimInfo.amount;
|
||||
} else if (this.state.myClaimMetadata) {
|
||||
// Just changed away from a name we have a claim on, so clear pre-fill
|
||||
newState.bid = '';
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}, () => { // Assume an error means the name is available
|
||||
this.setState({
|
||||
name: name,
|
||||
nameResolved: false,
|
||||
myClaimExists: false,
|
||||
});
|
||||
});
|
||||
},
|
||||
handleBidChange: function(event) {
|
||||
|
@ -343,12 +340,15 @@ var PublishPage = React.createClass({
|
|||
<section className="card">
|
||||
<h4>LBRY Name</h4>
|
||||
<div className="form-row">
|
||||
lbry://<FormField type="text" ref="name" value={this.state.rawName} onChange={this.handleNameChange} />
|
||||
<FormField type="text" ref="name" value={this.state.rawName} onChange={this.handleNameChange} />
|
||||
{
|
||||
(!this.state.name ? '' :
|
||||
(! this.state.nameResolved ? <em> The name <strong>{this.state.name}</strong> is available.</em>
|
||||
: (this.state.myClaimExists ? <em> You already have a claim on the name <strong>{this.state.name}</strong>. You can use this page to update your claim.</em>
|
||||
: <em> The name <strong>{this.state.name}</strong> is currently claimed for <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit' : 'credits'}.</em>)))
|
||||
(!this.state.name
|
||||
? null
|
||||
: (!this.state.nameResolved
|
||||
? <em> The name <strong>{this.state.name}</strong> is available.</em>
|
||||
: (this.state.myClaimExists
|
||||
? <em> You already have a claim on the name <strong>{this.state.name}</strong>. You can use this page to update your claim.</em>
|
||||
: <em> The name <strong>{this.state.name}</strong> is currently claimed for <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit' : 'credits'}.</em>)))
|
||||
}
|
||||
<div className="help">What LBRY name would you like to claim for this file?</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import lighthouse from '../lighthouse.js';
|
||||
import uri from '../uri.js';
|
||||
import {CreditAmount, Thumbnail} from '../component/common.js';
|
||||
import {FileActions} from '../component/file-actions.js';
|
||||
import {Link} from '../component/link.js';
|
||||
|
@ -16,22 +17,16 @@ var formatItemImgStyle = {
|
|||
|
||||
var FormatItem = React.createClass({
|
||||
propTypes: {
|
||||
claimInfo: React.PropTypes.object,
|
||||
metadata: React.PropTypes.object,
|
||||
contentType: React.PropTypes.string,
|
||||
cost: React.PropTypes.number,
|
||||
name: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
outpoint: React.PropTypes.string,
|
||||
costIncludesData: React.PropTypes.bool,
|
||||
},
|
||||
render: function() {
|
||||
var claimInfo = this.props.claimInfo;
|
||||
var thumbnail = claimInfo.thumbnail;
|
||||
var title = claimInfo.title;
|
||||
var description = claimInfo.description;
|
||||
var author = claimInfo.author;
|
||||
var language = claimInfo.language;
|
||||
var license = claimInfo.license;
|
||||
var fileContentType = (claimInfo.content_type || claimInfo['content-type']);
|
||||
var mediaType = lbry.getMediaType(fileContentType);
|
||||
const {thumbnail, author, title, description, language, license} = this.props.metadata;
|
||||
const mediaType = lbry.getMediaType(this.props.contentType);
|
||||
var costIncludesData = this.props.costIncludesData;
|
||||
var cost = this.props.cost || 0.0;
|
||||
|
||||
|
@ -46,7 +41,7 @@ var FormatItem = React.createClass({
|
|||
<table className="table-standard">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Content-Type</td><td>{fileContentType}</td>
|
||||
<td>Content-Type</td><td>{this.props.contentType}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cost</td><td><CreditAmount amount={cost} isEstimate={!costIncludesData}/></td>
|
||||
|
@ -63,7 +58,7 @@ var FormatItem = React.createClass({
|
|||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<FileActions streamName={this.props.name} outpoint={this.props.outpoint} metadata={claimInfo} />
|
||||
<FileActions uri={this._uri} outpoint={this.props.outpoint} metadata={this.props.metadata} contentType={this.props.contentType} />
|
||||
<section>
|
||||
<Link href="https://lbry.io/dmca" label="report" className="button-text-help" />
|
||||
</section>
|
||||
|
@ -75,17 +70,15 @@ var FormatItem = React.createClass({
|
|||
|
||||
var FormatsSection = React.createClass({
|
||||
propTypes: {
|
||||
claimInfo: React.PropTypes.object,
|
||||
uri: React.PropTypes.string,
|
||||
outpoint: React.PropTypes.string,
|
||||
metadata: React.PropTypes.object,
|
||||
contentType: React.PropTypes.string,
|
||||
cost: React.PropTypes.number,
|
||||
name: React.PropTypes.string,
|
||||
costIncludesData: React.PropTypes.bool,
|
||||
},
|
||||
render: function() {
|
||||
var name = this.props.name;
|
||||
var format = this.props.claimInfo;
|
||||
var title = format.title;
|
||||
|
||||
if(format == null)
|
||||
if(this.props.metadata == null)
|
||||
{
|
||||
return (
|
||||
<div>
|
||||
|
@ -95,41 +88,46 @@ var FormatsSection = React.createClass({
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className="meta">lbry://{name}</div>
|
||||
<h2>{title}</h2>
|
||||
<div className="meta">{this.props.uri}</div>
|
||||
<h2>{this.props.metadata.title}</h2>
|
||||
{/* In future, anticipate multiple formats, just a guess at what it could look like
|
||||
// var formats = this.props.claimInfo.formats
|
||||
// var formats = this.props.metadata.formats
|
||||
// return (<tbody>{formats.map(function(format,i){ */}
|
||||
<FormatItem claimInfo={format} cost={this.props.cost} name={this.props.name} costIncludesData={this.props.costIncludesData} />
|
||||
<FormatItem metadata={this.props.metadata} contentType={this.props.contentType} cost={this.props.cost} uri={this.props.uri} outpoint={this.props.outpoint} costIncludesData={this.props.costIncludesData} />
|
||||
{/* })}</tbody>); */}
|
||||
</div>);
|
||||
}
|
||||
});
|
||||
|
||||
var DetailPage = React.createClass({
|
||||
var ShowPage = React.createClass({
|
||||
_uri: null,
|
||||
|
||||
propTypes: {
|
||||
name: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
metadata: null,
|
||||
contentType: null,
|
||||
cost: null,
|
||||
costIncludesData: null,
|
||||
nameLookupComplete: null,
|
||||
uriLookupComplete: null,
|
||||
};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
document.title = 'lbry://' + this.props.name;
|
||||
this._uri = uri.normalizeLbryUri(this.props.uri);
|
||||
document.title = this._uri;
|
||||
|
||||
lbry.claim_show({name: this.props.name}, ({name, txid, nout, value}) => {
|
||||
lbry.resolve({uri: this._uri}).then(({txid, nout, claim: {value: {stream: {metadata, source: {contentType}}}}}) => {
|
||||
this.setState({
|
||||
outpoint: txid + ':' + nout,
|
||||
metadata: value,
|
||||
nameLookupComplete: true,
|
||||
metadata: metadata,
|
||||
contentType: contentType,
|
||||
uriLookupComplete: true,
|
||||
});
|
||||
});
|
||||
|
||||
lbry.getCostInfoForName(this.props.name, ({cost, includesData}) => {
|
||||
lbry.getCostInfo(this._uri, ({cost, includesData}) => {
|
||||
this.setState({
|
||||
cost: cost,
|
||||
costIncludesData: includesData,
|
||||
|
@ -141,21 +139,15 @@ var DetailPage = React.createClass({
|
|||
return null;
|
||||
}
|
||||
|
||||
const name = this.props.name;
|
||||
const costIncludesData = this.state.costIncludesData;
|
||||
const metadata = this.state.metadata;
|
||||
const cost = this.state.cost;
|
||||
const outpoint = this.state.outpoint;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<section className="card">
|
||||
{this.state.nameLookupComplete ? (
|
||||
<FormatsSection name={name} outpoint={outpoint} claimInfo={metadata} cost={cost} costIncludesData={costIncludesData} />
|
||||
{this.state.uriLookupComplete ? (
|
||||
<FormatsSection uri={this._uri} outpoint={this.state.outpoint} metadata={this.state.metadata} cost={this.state.cost} costIncludesData={this.state.costIncludesData} contentType={this.state.contentType} />
|
||||
) : (
|
||||
<div>
|
||||
<h2>No content</h2>
|
||||
There is no content available at the name <strong>lbry://{this.props.name}</strong>. If you reached this page from a link within the LBRY interface, please <Link href="?report" label="report a bug" />. Thanks!
|
||||
There is no content available at <strong>{this._uri}</strong>. If you reached this page from a link within the LBRY interface, please <Link href="?report" label="report a bug" />. Thanks!
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
@ -163,4 +155,4 @@ var DetailPage = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
export default DetailPage;
|
||||
export default ShowPage;
|
||||
|
|
|
@ -15,7 +15,7 @@ var WatchPage = React.createClass({
|
|||
_outpoint: null,
|
||||
|
||||
propTypes: {
|
||||
name: React.PropTypes.string,
|
||||
uri: React.PropTypes.string,
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
|
@ -27,7 +27,7 @@ var WatchPage = React.createClass({
|
|||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
lbry.get({name: this.props.name}).then((fileInfo) => {
|
||||
lbry.get({uri: this.props.uri}).then((fileInfo) => {
|
||||
this._outpoint = fileInfo.outpoint;
|
||||
this.updateLoadStatus();
|
||||
});
|
||||
|
|
14
ui/js/uri.js
14
ui/js/uri.js
|
@ -74,12 +74,12 @@ uri.parseLbryUri = function(lbryUri, requireProto=false) {
|
|||
throw new Error(`Invalid claim ID ${claimId}.`);
|
||||
}
|
||||
|
||||
if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]+$/)) {
|
||||
throw new Error('Bid position must be a number.');
|
||||
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
|
||||
throw new Error('Claim sequence must be a number.');
|
||||
}
|
||||
|
||||
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]+$/)) {
|
||||
throw new Error('Claim sequence must be a number.');
|
||||
if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) {
|
||||
throw new Error('Bid position must be a number.');
|
||||
}
|
||||
|
||||
// Validate path
|
||||
|
@ -115,4 +115,10 @@ uri.buildLbryUri = function(uriObj, includeProto=true) {
|
|||
(path ? `/${path}` : '');
|
||||
}
|
||||
|
||||
/* Takes a parseable LBRY URI and converts it to standard, canonical format (currently this just
|
||||
* consists of making sure it has a lbry:// prefix) */
|
||||
uri.normalizeLbryUri = function(lbryUri) {
|
||||
return uri.buildLbryUri(uri.parseLbryUri(lbryUri));
|
||||
}
|
||||
|
||||
export default uri;
|
||||
|
|
Loading…
Reference in a new issue