Staging #1066
31 changed files with 263 additions and 171 deletions
|
@ -300,8 +300,8 @@ This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
|
|||
|
||||
## Security
|
||||
|
||||
We take security seriously. Please contact security@lbry.io regarding any security issues. [Our GPG key is here](https://lbry.io/faq/gpg-key) if you need it.
|
||||
We take security seriously. Please contact security@lbry.com regarding any security issues. [Our GPG key is here](https://lbry.com/faq/gpg-key) if you need it.
|
||||
|
||||
## Contact
|
||||
|
||||
The primary contact for this project is [@jessopb](mailto:jessop@lbry.io).
|
||||
The primary contact for this project is [@jessopb](mailto:jessop@lbry.com).
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"host": "public.chainquery.lbry.io",
|
||||
"host": "public.chainquery.lbry.com",
|
||||
"port": "3306",
|
||||
"timeout": 30,
|
||||
"database": "chainquery",
|
||||
|
|
|
@ -18,12 +18,11 @@
|
|||
"host": "https://www.example.com",
|
||||
"description": "A decentralized hosting platform built on LBRY",
|
||||
"twitter": false,
|
||||
"blockListEndpoint": "https://api.lbry.io/file/list_blocked"
|
||||
"blockListEndpoint": "https://api.lbry.com/file/list_blocked"
|
||||
},
|
||||
"publishing": {
|
||||
"primaryClaimAddress": null,
|
||||
"uploadDirectory": "/home/lbry/Uploads",
|
||||
"lbrynetHome": "/CURRENTLYUNUSED",
|
||||
"thumbnailChannel": null,
|
||||
"thumbnailChannelId": null,
|
||||
"additionalClaimAddresses": [],
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import * as actions from '../constants/show_action_types';
|
||||
import {
|
||||
ASSET_DETAILS,
|
||||
ASSET_LITE,
|
||||
CHANNEL,
|
||||
SPECIAL_ASSET,
|
||||
} from '../constants/show_request_types';
|
||||
import { ASSET_DETAILS, ASSET_LITE, CHANNEL, SPECIAL_ASSET } from '../constants/show_request_types';
|
||||
|
||||
// basic request parsing
|
||||
export function onHandleShowPageUri (params, url) {
|
||||
export function onHandleShowPageUri(params, url) {
|
||||
return {
|
||||
type: actions.HANDLE_SHOW_URI,
|
||||
data: {
|
||||
|
@ -17,7 +12,7 @@ export function onHandleShowPageUri (params, url) {
|
|||
};
|
||||
}
|
||||
|
||||
export function onHandleShowHomepage (params, url) {
|
||||
export function onHandleShowHomepage(params, url) {
|
||||
return {
|
||||
type: actions.HANDLE_SHOW_HOMEPAGE,
|
||||
data: {
|
||||
|
@ -27,14 +22,14 @@ export function onHandleShowHomepage (params, url) {
|
|||
};
|
||||
}
|
||||
|
||||
export function onRequestError (error) {
|
||||
export function onRequestError(error) {
|
||||
return {
|
||||
type: actions.REQUEST_ERROR,
|
||||
data: error,
|
||||
};
|
||||
}
|
||||
|
||||
export function onNewChannelRequest (channelName, channelId) {
|
||||
export function onNewChannelRequest(channelName, channelId) {
|
||||
const requestType = CHANNEL;
|
||||
const requestId = `cr#${channelName}#${channelId}`;
|
||||
return {
|
||||
|
@ -43,7 +38,7 @@ export function onNewChannelRequest (channelName, channelId) {
|
|||
};
|
||||
}
|
||||
|
||||
export function onNewSpecialAssetRequest (name) {
|
||||
export function onNewSpecialAssetRequest(name) {
|
||||
const requestType = SPECIAL_ASSET;
|
||||
const requestId = `sar#${name}`;
|
||||
return {
|
||||
|
@ -52,7 +47,7 @@ export function onNewSpecialAssetRequest (name) {
|
|||
};
|
||||
}
|
||||
|
||||
export function onNewAssetRequest (name, id, channelName, channelId, extension) {
|
||||
export function onNewAssetRequest(name, id, channelName, channelId, extension) {
|
||||
const requestType = extension ? ASSET_LITE : ASSET_DETAILS;
|
||||
const requestId = `ar#${name}#${id}#${channelName}#${channelId}`;
|
||||
return {
|
||||
|
@ -65,14 +60,14 @@ export function onNewAssetRequest (name, id, channelName, channelId, extension)
|
|||
id,
|
||||
channel: {
|
||||
name: channelName,
|
||||
id : channelId,
|
||||
id: channelId,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function onRequestUpdate (requestType, requestId) {
|
||||
export function onRequestUpdate(requestType, requestId) {
|
||||
return {
|
||||
type: actions.REQUEST_UPDATE,
|
||||
data: {
|
||||
|
@ -82,7 +77,7 @@ export function onRequestUpdate (requestType, requestId) {
|
|||
};
|
||||
}
|
||||
|
||||
export function addRequestToRequestList (id, error, key) {
|
||||
export function addRequestToRequestList(id, error, key) {
|
||||
return {
|
||||
type: actions.REQUEST_LIST_ADD,
|
||||
data: { id, error, key },
|
||||
|
@ -91,21 +86,21 @@ export function addRequestToRequestList (id, error, key) {
|
|||
|
||||
// asset actions
|
||||
|
||||
export function addAssetToAssetList (id, error, name, claimId, shortId, claimData, claimViews) {
|
||||
export function addAssetToAssetList(id, error, name, claimId, shortId, claimData, claimViews) {
|
||||
return {
|
||||
type: actions.ASSET_ADD,
|
||||
data: { id, error, name, claimId, shortId, claimData, claimViews },
|
||||
};
|
||||
}
|
||||
|
||||
export function updateAssetViewsInList (id, claimId, claimViews) {
|
||||
export function updateAssetViewsInList(id, claimId, claimViews) {
|
||||
return {
|
||||
type: actions.ASSET_VIEWS_UPDATE,
|
||||
data: { id, claimId, claimViews },
|
||||
};
|
||||
}
|
||||
|
||||
export function removeAsset (data) {
|
||||
export function removeAsset(data) {
|
||||
return {
|
||||
type: actions.ASSET_REMOVE,
|
||||
data,
|
||||
|
@ -114,7 +109,7 @@ export function removeAsset (data) {
|
|||
|
||||
// channel actions
|
||||
|
||||
export function addNewChannelToChannelList (id, name, shortId, longId, claimsData) {
|
||||
export function addNewChannelToChannelList(id, name, shortId, longId, claimsData) {
|
||||
return {
|
||||
type: actions.CHANNEL_ADD,
|
||||
data: {
|
||||
|
@ -127,39 +122,47 @@ export function addNewChannelToChannelList (id, name, shortId, longId, claimsDat
|
|||
};
|
||||
}
|
||||
|
||||
export function onUpdateChannelClaims (channelKey, name, longId, page) {
|
||||
export function onUpdateChannelClaims(channelKey, name, longId, page) {
|
||||
return {
|
||||
type: actions.CHANNEL_CLAIMS_UPDATE_ASYNC,
|
||||
data: {channelKey, name, longId, page},
|
||||
data: { channelKey, name, longId, page },
|
||||
};
|
||||
}
|
||||
|
||||
export function updateChannelClaims (channelListId, claimsData) {
|
||||
export function updateChannelClaims(channelListId, claimsData) {
|
||||
return {
|
||||
type: actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED,
|
||||
data: {channelListId, claimsData},
|
||||
data: { channelListId, claimsData },
|
||||
};
|
||||
}
|
||||
|
||||
// display a file
|
||||
|
||||
export function fileRequested (name, claimId) {
|
||||
export function fileRequested(name, claimId) {
|
||||
return {
|
||||
type: actions.FILE_REQUESTED,
|
||||
data: { name, claimId },
|
||||
};
|
||||
}
|
||||
|
||||
export function updateFileAvailability (status) {
|
||||
export function updateFileAvailability(status) {
|
||||
return {
|
||||
type: actions.FILE_AVAILABILITY_UPDATE,
|
||||
data: status,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateDisplayAssetError (error) {
|
||||
export function updateDisplayAssetError(error) {
|
||||
return {
|
||||
type: actions.DISPLAY_ASSET_ERROR,
|
||||
data: error,
|
||||
};
|
||||
}
|
||||
|
||||
// viewer settings
|
||||
export function toggleDetailsExpanded(isExpanded) {
|
||||
return {
|
||||
type: actions.TOGGLE_DETAILS_EXPANDED,
|
||||
data: isExpanded,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ const AboutSpeechDetails = () => {
|
|||
</Row>
|
||||
<Row>
|
||||
<p className={'text--large'}>
|
||||
Spee.ch is a media-hosting site that reads from and publishes content to the <a className='link--primary' href='https://lbry.io'>LBRY</a> blockchain.
|
||||
Spee.ch is a media-hosting site that reads from and publishes content to the <a className='link--primary' href='https://lbry.com'>LBRY</a> blockchain.
|
||||
</p>
|
||||
<p className={'text--large'}>
|
||||
Spee.ch is a hosting service, but with the added benefit that it stores your content on a decentralized network of computers -- the <a className='link--primary' href='https://lbry.io/get'>LBRY</a> network. This means that your images are stored in multiple locations without a single point of failure.
|
||||
Spee.ch is a hosting service, but with the added benefit that it stores your content on a decentralized network of computers -- the <a className='link--primary' href='https://lbry.com/get'>LBRY</a> network. This means that your images are stored in multiple locations without a single point of failure.
|
||||
</p>
|
||||
</Row>
|
||||
<Row>
|
||||
|
@ -26,7 +26,7 @@ const AboutSpeechDetails = () => {
|
|||
If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a className='link--primary' href='https://github.com/lbryio/spee.ch'>github repo</a> and go to town!
|
||||
</p>
|
||||
<p className={'text--large'}>
|
||||
If you want to improve spee.ch, join our <a className='link--primary' href='https://chat.lbry.io'>discord channel</a> or solve one of our <a className='link--primary' href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.
|
||||
If you want to improve spee.ch, join our <a className='link--primary' href='https://chat.lbry.com'>discord channel</a> or solve one of our <a className='link--primary' href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.
|
||||
</p>
|
||||
</Row>
|
||||
</div>
|
||||
|
|
|
@ -3,9 +3,13 @@ import Row from '@components/Row';
|
|||
|
||||
const AssetInfoFooter = ({ assetUrl, name }) => {
|
||||
return (
|
||||
<div className='asset-footer'>
|
||||
<div className="asset-footer">
|
||||
<p>
|
||||
Hosted via the <a className={'link--primary'} href={'https://lbry.io/get'} target={'_blank'}>LBRY</a> blockchain
|
||||
Hosted via the{' '}
|
||||
<a className={'link--primary'} href={'https://lbry.com/get'} target={'_blank'}>
|
||||
LBRY
|
||||
</a>{' '}
|
||||
blockchain
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,19 +2,19 @@ import React from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||
import * as Icon from 'react-feather';
|
||||
import Img from 'react-image';
|
||||
|
||||
const AssetPreview = ({ defaultThumbnail, claimData }) => {
|
||||
const {name, fileExt, contentType, thumbnail, title, blocked, transactionTime} = claimData;
|
||||
const {name, fileExt, contentType, thumbnail, title, blocked, transactionTime = 0} = claimData;
|
||||
const showUrl = createCanonicalLink({asset: {...claimData}});
|
||||
console.log(transactionTime)
|
||||
const embedUrl = `${showUrl}.${fileExt}`;
|
||||
const ago = Date.now()/1000 - transactionTime;
|
||||
const ago = Date.now() / 1000 - transactionTime;
|
||||
const dayInSeconds = 60 * 60 * 24;
|
||||
const monthInSeconds = dayInSeconds * 30;
|
||||
const yearInSeconds = dayInSeconds * 365;
|
||||
let when;
|
||||
|
||||
if (ago < dayInSeconds) {
|
||||
if (ago < dayInSeconds || transactionTime < 1) {
|
||||
when = 'Just today';
|
||||
} else if (ago < monthInSeconds) {
|
||||
when = `${Math.floor(ago / dayInSeconds)} d ago`;
|
||||
|
@ -52,10 +52,14 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
|
|||
return (
|
||||
<Link to={showUrl} className='asset-preview'>
|
||||
<div className='asset-preview__image-box'>
|
||||
<img
|
||||
className={'asset-preview__image'}
|
||||
src={thumb || defaultThumbnail}
|
||||
<Img
|
||||
src={[
|
||||
thumb,
|
||||
defaultThumbnail,
|
||||
'/assets/img/default_thumb.jpg',
|
||||
]}
|
||||
alt={name}
|
||||
className={'asset-preview__image'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
const PublishFinePrint = () => {
|
||||
return (
|
||||
<p className={'text--extra-small text--secondary'}>
|
||||
By clicking 'Publish', you affirm that you have the rights to publish this content to the LBRY network, and that you understand the properties of publishing it to a decentralized, user-controlled network. <a className='link--primary' target='_blank' href='https://lbry.io/learn'>Read more.</a>
|
||||
By clicking 'Publish', you affirm that you have the rights to publish this content to the LBRY network, and that you understand the properties of publishing it to a decentralized, user-controlled network. <a className='link--primary' target='_blank' href='https://lbry.com/learn'>Read more.</a>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -24,3 +24,4 @@ export const CHANNEL_CLAIMS_UPDATE_SUCCEEDED = 'CHANNEL_CLAIMS_UPDATE_SUCCEEDED'
|
|||
export const FILE_REQUESTED = 'FILE_REQUESTED';
|
||||
export const FILE_AVAILABILITY_UPDATE = 'FILE_AVAILABILITY_UPDATE';
|
||||
export const DISPLAY_ASSET_ERROR = 'DISPLAY_ASSET_ERROR';
|
||||
export const TOGGLE_DETAILS_EXPANDED = 'TOGGLE_DETAILS_EXPANDED';
|
||||
|
|
|
@ -17,7 +17,7 @@ class BlockedRight extends React.PureComponent {
|
|||
return (
|
||||
<div className={'asset-blocked__text'} >
|
||||
<p>In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications.</p>
|
||||
<p><a href={'https://lbry.io/faq/dmca'} >Click here</a> for more information.</p>
|
||||
<p><a href={'https://lbry.com/faq/dmca'} >Click here</a> for more information.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import ProgressBar from '@components/ProgressBar';
|
|||
import { LOCAL_CHECK, UNAVAILABLE, ERROR, AVAILABLE } from '../../constants/asset_display_states';
|
||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||
import FileViewer from '@components/FileViewer';
|
||||
import isBot from 'isbot';
|
||||
import Img from 'react-image';
|
||||
|
||||
class AvailableContent extends React.Component {
|
||||
render () {
|
||||
|
@ -15,20 +17,23 @@ class AvailableContent extends React.Component {
|
|||
case 'image/gif':
|
||||
case 'image/svg+xml':
|
||||
return (
|
||||
<img
|
||||
className='asset-image'
|
||||
src={sourceUrl}
|
||||
<Img
|
||||
src={[
|
||||
sourceUrl,
|
||||
'/assets/img/default_thumb.jpg',
|
||||
]}
|
||||
alt={name}
|
||||
className={'asset-image'}
|
||||
/>
|
||||
);
|
||||
case 'video/mp4':
|
||||
return (
|
||||
<video
|
||||
className='asset-video'
|
||||
controls poster={thumbnail}
|
||||
controls poster={!!thumbnail && thumbnail || '/assets/img/default_thumb.jpg'}
|
||||
>
|
||||
<source
|
||||
src={sourceUrl}
|
||||
src={!!sourceUrl && sourceUrl}
|
||||
/>
|
||||
<p>Your browser does not support the <code>video</code> element.</p>
|
||||
</video>
|
||||
|
@ -36,14 +41,25 @@ class AvailableContent extends React.Component {
|
|||
case 'text/markdown':
|
||||
|
||||
return (
|
||||
<div className={'asset-document'}><FileViewer sourceUrl={sourceUrl}/></div>
|
||||
(isBot(window.navigator.userAgent))
|
||||
? (
|
||||
<img
|
||||
className='asset-image'
|
||||
src={'/assets/img/default_thumb.jpg'}
|
||||
alt={'markdown available on page load'}
|
||||
/>
|
||||
)
|
||||
: <div className={'asset-document'}><FileViewer sourceUrl={!!sourceUrl && sourceUrl}/></div>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<img
|
||||
className='asset-image'
|
||||
src={thumbnail}
|
||||
<Img
|
||||
src={[
|
||||
thumbnail,
|
||||
'/assets/img/default_thumb.jpg',
|
||||
]}
|
||||
alt={name}
|
||||
className={'asset-image'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -76,7 +92,7 @@ class AssetDisplay extends React.Component {
|
|||
<div>
|
||||
<p>Sit tight, we're searching the LBRY blockchain for your asset!</p>
|
||||
<ProgressBar size={12} />
|
||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.io/faq/what-is-lbry'>Learn more.</a></p>
|
||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.com/faq/what-is-lbry'>Learn more.</a></p>
|
||||
</div>
|
||||
}
|
||||
{(status === ERROR) && (
|
||||
|
@ -87,7 +103,7 @@ class AssetDisplay extends React.Component {
|
|||
) : (
|
||||
<div>
|
||||
<Row>
|
||||
<p>Unfortunately, we couldn't download your asset from LBRY. You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>LBRY discord</a>.</p>
|
||||
<p>Unfortunately, we couldn't download your asset from LBRY. You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.com' target='_blank'>LBRY discord</a>.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<p id='error-message'><i>{error}</i></p>
|
||||
|
|
|
@ -186,7 +186,7 @@ class AssetInfo extends React.Component {
|
|||
</a>
|
||||
<a
|
||||
className={'link--primary'}
|
||||
href={`https://open.lbry.io/${createPermanentURI(asset)}`}
|
||||
href={`https://open.lbry.com/${createPermanentURI(asset)}`}
|
||||
download={name}
|
||||
>
|
||||
LBRY URL
|
||||
|
@ -194,7 +194,7 @@ class AssetInfo extends React.Component {
|
|||
<a
|
||||
className={'link--primary'}
|
||||
target='_blank'
|
||||
href='https://lbry.io/dmca'
|
||||
href='https://lbry.com/dmca'
|
||||
>
|
||||
Report
|
||||
</a>
|
||||
|
|
|
@ -38,7 +38,7 @@ class PublishStatus extends React.Component {
|
|||
<ProgressBar size={12} />
|
||||
</Row>
|
||||
<Row>
|
||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.io/faq/what-is-lbry'>Learn more.</a></p>
|
||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.com/faq/what-is-lbry'>Learn more.</a></p>
|
||||
</Row>
|
||||
</div>
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ class PublishStatus extends React.Component {
|
|||
<p className={'text--strong'}>{message}</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<p>For help, post the above error text in the #speech channel on the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>lbry discord</a></p>
|
||||
<p>For help, post the above error text in the #speech channel on the <a className='link--primary' href='https://chat.lbry.com' target='_blank'>lbry discord</a></p>
|
||||
</Row>
|
||||
<Row>
|
||||
<ButtonSecondary
|
||||
|
|
|
@ -15,7 +15,7 @@ class FaqPage extends React.Component {
|
|||
</Row>
|
||||
<Row>
|
||||
<h3>What is spee.ch?</h3>
|
||||
<p>Spee.ch is a media-hosting site that reads from and publishes content to the <a href='http://lbry.io/'>LBRY blockchain</a>.</p>
|
||||
<p>Spee.ch is a media-hosting site that reads from and publishes content to the <a href='http://lbry.com/'>LBRY blockchain</a>.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<h3>OK But Why Should I Care?</h3>
|
||||
|
@ -29,7 +29,7 @@ class FaqPage extends React.Component {
|
|||
<p>It’s easy. Drag the image or video file of your choice into the center of the spee.ch homepage.</p>
|
||||
<p>Spee.ch is currently best suited for web optimized MP4 video and standard image filetypes (JPEG, PNG, GIF).</p>
|
||||
<p>If you want to refer to a piece of content repeatedly, or to build a collection of related content, you could create a channel. Channels work both for private collections and for public repositories. There’s more info about how to do this <a href='https://spee.ch/login'>on the channel page</a>.</p>
|
||||
<p>Published files will be wiewable and embeddable with any web browser and accesible in the LBRY app. You can also use spee.ch to view free and non-NSFW content published on LBRY network from LBRY app. You just need to replace "lbry://" with "http://spee.ch/" in the URL.</p>
|
||||
<p>Published files will be viewable and embeddable with any web browser and accesible in the LBRY app. You can also use spee.ch to view free and non-NSFW content published on LBRY network from LBRY app. You just need to replace "lbry://" with "http://spee.ch/" in the URL.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<h3>How Long Does Content Stay on Spee.ch?</h3>
|
||||
|
@ -38,7 +38,7 @@ class FaqPage extends React.Component {
|
|||
<Row>
|
||||
<h3>Contribute</h3>
|
||||
<p>If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a href='https://github.com/lbryio/spee.ch'>github repo</a> and go to town!</p>
|
||||
<p>If you want to improve spee.ch, join <a href='https://chat.lbry.io/'>our discord channel</a> or solve one of our <a href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.</p>
|
||||
<p>If you want to improve spee.ch, join <a href='https://chat.lbry.com/'>our discord channel</a> or solve one of our <a href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.</p>
|
||||
</Row>
|
||||
</Row>
|
||||
</PageLayout>
|
||||
|
|
|
@ -7,7 +7,7 @@ const MultisiteContent = () => {
|
|||
<p className='text--pull-quote'>Introducing Spee.ch Multisite</p>
|
||||
<p>Hi there! My name is <a href={'https://github.com/billbitt'} target={'_blank'}>Bill</a>, and I’d like to speak with you about Spee.ch. No, not ‘speech,’ ‘<i><a href={'https://spee.ch'} target={'_blank'}>Spee.ch.</a></i>’ You know what, just read on...</p>
|
||||
<h2>A Little Background</h2>
|
||||
<p>Wow, time flies! A little over a year ago Spee.ch was nothing more than a glimmer in the eye of LBRY CEO Jeremy Kaufman. At that time, the <a href={'https://lbry.io/faq/what-is-lbry'} target={'_blank'}>LBRY protocol</a> was still so early in its development, that there were no web-based applications for interacting with the LBRY blockchain. But then, something beautiful happened. On March 29th, 2017, Jeremy sat down with Jack, and together they <a href={'https://www.youtube.com/watch?v=C9LCapt_OYw'} target={'_blank'}>live coded a single-page PHP site</a> that could publish images to the LBRY network. And just like that, Spee.ch was born!</p>
|
||||
<p>Wow, time flies! A little over a year ago Spee.ch was nothing more than a glimmer in the eye of LBRY CEO Jeremy Kaufman. At that time, the <a href={'https://lbry.com/faq/what-is-lbry'} target={'_blank'}>LBRY protocol</a> was still so early in its development, that there were no web-based applications for interacting with the LBRY blockchain. But then, something beautiful happened. On March 29th, 2017, Jeremy sat down with Jack, and together they <a href={'https://www.youtube.com/watch?v=C9LCapt_OYw'} target={'_blank'}>live coded a single-page PHP site</a> that could publish images to the LBRY network. And just like that, Spee.ch was born!</p>
|
||||
<p>Being that LBRY is an open source project, Jeremy ended the session by inviting community members who were interested in the project to take the reigns and see where Spee.ch could go. I was one of the devs that did just that, and it wasn’t long before I was on a weekly call dedicated to this project with contributors from around the world.</p>
|
||||
<p>At this point in time, the vision for Spee.ch was pretty simple: create a web-based hosting service that used the LBRY network as a database for free image and video sharing. In other words, an ‘imgur on the blockchain.’</p>
|
||||
<h2>Growth</h2>
|
||||
|
@ -41,7 +41,7 @@ const MultisiteContent = () => {
|
|||
<li>Where: Google Hangouts</li>
|
||||
<li>Link: <a href={'https://meet.google.com/aex-ghqg-kcs'} target={'_blank'}>meet.google.com/aex-ghqg-kcs</a></li>
|
||||
<li>System Requirements: If you have a server, please make sure you have MySql, Node and NPM installed. If you need help installing the above, or if you need a server to run your own instance on, please join the Hangout 30 minutes ahead of time and we will help get you set up =]</li>
|
||||
<li>Questions: hello@lbry.io</li>
|
||||
<li>Questions: hello@lbry.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectAsset } from '../../selectors/show';
|
||||
import { selectAsset, selectDetailsExpanded } from '../../selectors/show';
|
||||
import { toggleDetailsExpanded } from '../../actions/show';
|
||||
|
||||
import View from './view';
|
||||
|
||||
const mapStateToProps = ({ show }) => {
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
asset: selectAsset(show),
|
||||
asset: selectAsset(state.show),
|
||||
detailsExpanded: selectDetailsExpanded(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, null)(View);
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onToggleDetailsExpanded: value => {
|
||||
dispatch(toggleDetailsExpanded(value));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(View);
|
||||
|
|
|
@ -11,24 +11,15 @@ class ShowAssetDetails extends React.Component {
|
|||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.collapse = this.collapse.bind(this);
|
||||
// this.storageKey = 'vert-split-state-' + this.props.name;
|
||||
// const closed = window && window.localStorage
|
||||
// ? !!window.localStorage.getItem(this.storageKey) : false;
|
||||
const closed = true;
|
||||
this.state = { closed: closed };
|
||||
this.toggleExpandDetails = this.toggleExpandDetails.bind(this);
|
||||
}
|
||||
|
||||
collapse () {
|
||||
this.setState({ closed: !this.state.closed });
|
||||
// if (window && window.localStorage) {
|
||||
// window.localStorage.setItem(this.storageKey, !this.state.closed);
|
||||
// }
|
||||
// document.querySelectorAll(`[data-name='${this.props.name}']`).forEach(el => el.classList.toggle('closed'));
|
||||
toggleExpandDetails () {
|
||||
this.props.onToggleDetailsExpanded(!this.props.detailsExpanded);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { asset } = this.props;
|
||||
const { asset, detailsExpanded } = this.props;
|
||||
if (asset) {
|
||||
const { claimData: { name, blocked } } = asset;
|
||||
if (!blocked) {
|
||||
|
@ -37,16 +28,16 @@ class ShowAssetDetails extends React.Component {
|
|||
pageTitle={`${name} - details`}
|
||||
asset={asset}
|
||||
>
|
||||
<div className="asset-main">
|
||||
<div className='asset-main'>
|
||||
<AssetTitle />
|
||||
<AssetDisplay />
|
||||
<div>
|
||||
<button className='collapse-button' onClick={this.collapse}>
|
||||
{this.state.closed ? <Icon.PlusCircle className='plus-icon' /> : <Icon.MinusCircle />}
|
||||
<button className='collapse-button' onClick={this.toggleExpandDetails}>
|
||||
{detailsExpanded ? <Icon.MinusCircle /> : <Icon.PlusCircle className='plus-icon' /> }
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{!this.state.closed && <AssetInfo />}
|
||||
{detailsExpanded && <AssetInfo />}
|
||||
|
||||
</PageLayout>
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ const AssetLiteFooter = ({ name, claimId }) => {
|
|||
return (
|
||||
<SpaceAround>
|
||||
<p className={'text--extra-small'}>
|
||||
<Link className='link--primary' to={`/${claimId}/${name}`}> hosted on spee.ch</Link> via the <a className='link--primary' href={'https://lbry.io/get'} target={'_blank'}>LBRY</a> blockchain
|
||||
<Link className='link--primary' to={`/${claimId}/${name}`}> hosted on spee.ch</Link> via the <a className='link--primary' href={'https://lbry.com/get'} target={'_blank'}>LBRY</a> blockchain
|
||||
</p>
|
||||
</SpaceAround>
|
||||
);
|
||||
|
|
|
@ -13,15 +13,15 @@ class TosPage extends React.Component {
|
|||
<Row>
|
||||
<h1>Terms of Service</h1>
|
||||
<p>Last updated: September 25, 2018</p>
|
||||
<p>Please read these Terms of Service ("Terms", "Terms of Service") carefully before using the <a className='link--primary' href='https://spee.ch'>https://spee.ch</a> website (the "Service") operated by <a className='link--primary' href='https://lbry.io'>LBRY INC</a> ("us", "we", or "our").</p>
|
||||
<p>Please read these Terms of Service ("Terms", "Terms of Service") carefully before using the <a className='link--primary' href='https://spee.ch'>https://spee.ch</a> website (the "Service") operated by <a className='link--primary' href='https://lbry.com'>LBRY INC</a> ("us", "we", or "our").</p>
|
||||
<p>Your access to and use of the Service is conditioned upon your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who wish to access or use the Service.</p>
|
||||
<p>By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you do not have permission to access the Service.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<h3>Links To Other Web Sites</h3>
|
||||
<p>Our Service may contain links to third party web sites or services that are not owned or controlled by <a className='link--primary' href='https://lbry.io'>LBRY INC</a></p>
|
||||
<p><a className='link--primary' href='https://lbry.io'>LBRY INC</a> has no control over, and assumes no responsibility for the content, privacy policies, or practices of any third party web sites or services. We do not warrant the offerings of any of these entities/individuals or their websites.</p>
|
||||
<p>You acknowledge and agree that <a className='link--primary' href='https://lbry.io'>LBRY INC</a> shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such third party web sites or services.</p>
|
||||
<p>Our Service may contain links to third party web sites or services that are not owned or controlled by <a className='link--primary' href='https://lbry.com'>LBRY INC</a></p>
|
||||
<p><a className='link--primary' href='https://lbry.com'>LBRY INC</a> has no control over, and assumes no responsibility for the content, privacy policies, or practices of any third party web sites or services. We do not warrant the offerings of any of these entities/individuals or their websites.</p>
|
||||
<p>You acknowledge and agree that <a className='link--primary' href='https://lbry.com'>LBRY INC</a> shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such third party web sites or services.</p>
|
||||
<p>We strongly advise you to read the terms and conditions and privacy policies of any third party web sites or services that you visit.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
|
@ -35,12 +35,12 @@ class TosPage extends React.Component {
|
|||
</Row>
|
||||
<Row>
|
||||
<h3>Limitation Of Liability</h3>
|
||||
<p>In no event shall <a className='link--primary' href='https://lbry.io'>LBRY INC</a>, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use the Service; (ii) any conduct or content of any third party on the Service; (iii) any content obtained from the Service; and (iv) unauthorized access, use or alteration of your transmissions or content, whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.</p>
|
||||
<p>In no event shall <a className='link--primary' href='https://lbry.com'>LBRY INC</a>, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use the Service; (ii) any conduct or content of any third party on the Service; (iii) any content obtained from the Service; and (iv) unauthorized access, use or alteration of your transmissions or content, whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<h3>Disclaimer</h3>
|
||||
<p>Your use of the Service is at your sole risk. The Service is provided on an "AS IS" and "AS AVAILABLE" basis. The Service is provided without warranties of any kind, whether express or implied, including, but not limited to, implied warranties of merchantability, fitness for a particular purpose, non-infringement or course of performance.</p>
|
||||
<p><a className='link--primary' href='https://lbry.io'>LBRY INC</a> its subsidiaries, affiliates, and its licensors do not warrant that a) the Service will function uninterrupted, secure or available at any particular time or location; b) any errors or defects will be corrected; c) the Service is free of viruses or other harmful components; or d) the results of using the Service will meet your requirements.</p>
|
||||
<p><a className='link--primary' href='https://lbry.com'>LBRY INC</a> its subsidiaries, affiliates, and its licensors do not warrant that a) the Service will function uninterrupted, secure or available at any particular time or location; b) any errors or defects will be corrected; c) the Service is free of viruses or other harmful components; or d) the results of using the Service will meet your requirements.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<h3>Exclusions</h3>
|
||||
|
@ -58,7 +58,7 @@ class TosPage extends React.Component {
|
|||
</Row>
|
||||
<Row>
|
||||
<h3>Contact Us</h3>
|
||||
<p>If you have any questions about these Terms, please <a className='link--primary' href='mailto:hello@lbry.io'>contact us</a>.</p>
|
||||
<p>If you have any questions about these Terms, please <a className='link--primary' href='mailto:hello@lbry.com'>contact us</a>.</p>
|
||||
</Row>
|
||||
</Row>
|
||||
</PageLayout>
|
||||
|
|
|
@ -4,19 +4,20 @@ import { LOCAL_CHECK, ERROR } from '../constants/asset_display_states';
|
|||
const initialState = {
|
||||
request: {
|
||||
error: null,
|
||||
type : null,
|
||||
id : null,
|
||||
type: null,
|
||||
id: null,
|
||||
},
|
||||
requestList : {},
|
||||
channelList : {},
|
||||
assetList : {},
|
||||
requestList: {},
|
||||
channelList: {},
|
||||
assetList: {},
|
||||
displayAsset: {
|
||||
error : null,
|
||||
error: null,
|
||||
status: LOCAL_CHECK,
|
||||
},
|
||||
detailsExpanded: true,
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
export default function(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
// handle request
|
||||
case actions.REQUEST_ERROR:
|
||||
|
@ -29,7 +30,7 @@ export default function (state = initialState, action) {
|
|||
return Object.assign({}, state, {
|
||||
request: Object.assign({}, state.request, {
|
||||
type: action.data.requestType,
|
||||
id : action.data.requestId,
|
||||
id: action.data.requestId,
|
||||
}),
|
||||
});
|
||||
// store requests
|
||||
|
@ -38,7 +39,7 @@ export default function (state = initialState, action) {
|
|||
requestList: Object.assign({}, state.requestList, {
|
||||
[action.data.id]: {
|
||||
error: action.data.error,
|
||||
key : action.data.key,
|
||||
key: action.data.key,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
@ -47,11 +48,11 @@ export default function (state = initialState, action) {
|
|||
return Object.assign({}, state, {
|
||||
assetList: Object.assign({}, state.assetList, {
|
||||
[action.data.id]: {
|
||||
error : action.data.error,
|
||||
name : action.data.name,
|
||||
claimId : action.data.claimId,
|
||||
shortId : action.data.shortId,
|
||||
claimData : action.data.claimData,
|
||||
error: action.data.error,
|
||||
name: action.data.name,
|
||||
claimId: action.data.claimId,
|
||||
shortId: action.data.shortId,
|
||||
claimData: action.data.claimData,
|
||||
claimViews: action.data.claimViews,
|
||||
},
|
||||
}),
|
||||
|
@ -76,7 +77,7 @@ export default function (state = initialState, action) {
|
|||
|
||||
return {
|
||||
...state,
|
||||
assetList : newAssetList,
|
||||
assetList: newAssetList,
|
||||
channelList: {
|
||||
...state.channelList,
|
||||
[channelId]: {
|
||||
|
@ -107,9 +108,9 @@ export default function (state = initialState, action) {
|
|||
return Object.assign({}, state, {
|
||||
channelList: Object.assign({}, state.channelList, {
|
||||
[action.data.id]: {
|
||||
name : action.data.name,
|
||||
longId : action.data.longId,
|
||||
shortId : action.data.shortId,
|
||||
name: action.data.name,
|
||||
longId: action.data.longId,
|
||||
shortId: action.data.shortId,
|
||||
claimsData: action.data.claimsData,
|
||||
},
|
||||
}),
|
||||
|
@ -117,9 +118,13 @@ export default function (state = initialState, action) {
|
|||
case actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED:
|
||||
return Object.assign({}, state, {
|
||||
channelList: Object.assign({}, state.channelList, {
|
||||
[action.data.channelListId]: Object.assign({}, state.channelList[action.data.channelListId], {
|
||||
claimsData: action.data.claimsData,
|
||||
}),
|
||||
[action.data.channelListId]: Object.assign(
|
||||
{},
|
||||
state.channelList[action.data.channelListId],
|
||||
{
|
||||
claimsData: action.data.claimsData,
|
||||
}
|
||||
),
|
||||
}),
|
||||
});
|
||||
// display an asset
|
||||
|
@ -132,10 +137,15 @@ export default function (state = initialState, action) {
|
|||
case actions.DISPLAY_ASSET_ERROR:
|
||||
return Object.assign({}, state, {
|
||||
displayAsset: Object.assign({}, state.displayAsset, {
|
||||
error : action.data,
|
||||
error: action.data,
|
||||
status: ERROR,
|
||||
}),
|
||||
});
|
||||
case actions.TOGGLE_DETAILS_EXPANDED:
|
||||
return {
|
||||
...state,
|
||||
detailsExpanded: action.data,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,16 @@ export const selectAsset = show => {
|
|||
const request = show.requestList[requestId] || null;
|
||||
const assetList = show.assetList;
|
||||
if (request && assetList) {
|
||||
const assetKey = request.key; // note: just store this in the request
|
||||
const assetKey = request.key; // note: just store this in the request
|
||||
asset = assetList[assetKey] || null;
|
||||
}
|
||||
return asset;
|
||||
};
|
||||
|
||||
export const selectShowState = (state) => {
|
||||
export const selectShowState = state => {
|
||||
return state.show;
|
||||
};
|
||||
|
||||
export const selectDetailsExpanded = state => {
|
||||
return state.show.detailsExpanded;
|
||||
};
|
||||
|
|
89
fullstart.md
89
fullstart.md
|
@ -1,74 +1,82 @@
|
|||
# Create Your Own Spee.ch!
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
### You will need the following tools installed
|
||||
|
||||
* Node (v8 LTS).
|
||||
* Make sure you install from the **Node** website [link](https://nodejs.org/en/download/).
|
||||
* npm (should come installed with Node).
|
||||
* Git
|
||||
* Curl
|
||||
* Tmux
|
||||
* Unzip
|
||||
- Node (v8 LTS).
|
||||
- Make sure you install from the **Node** website [link](https://nodejs.org/en/download/).
|
||||
- npm (should come installed with Node).
|
||||
- Git
|
||||
- Curl
|
||||
- Tmux
|
||||
- Unzip
|
||||
|
||||
### Make sure **npm** is up-to-date.
|
||||
|
||||
```
|
||||
$ npm update
|
||||
```
|
||||
|
||||
### Setup a Webserver to serve **Spee.ch** from Port **3000**.
|
||||
* If you are using a server provided by **lbry**, we will have **caddy** installed already.
|
||||
* If you are using your own server, make sure to have a web server installed and set up to serve from port **3000**.
|
||||
* Nginx instructions (recommended).
|
||||
* Insert directions for certbot before installing.
|
||||
* Install [Nginx](http://nginx.org/en/docs/install.html).
|
||||
* Create a config file called `spee.ch` in */etc/nginx/sites-available*
|
||||
* see example: [config file](https://github.com/lbryio/spee.ch/blob/master/nginx_example_config).
|
||||
* Rename all mentions of *sub.domain.com* with your subdomain name.
|
||||
* Run this command to link the sites-available.
|
||||
|
||||
- If you are using a server provided by **lbry**, we will have **caddy** installed already.
|
||||
- If you are using your own server, make sure to have a web server installed and set up to serve from port **3000**.
|
||||
- Nginx instructions (recommended).
|
||||
|
||||
- Insert directions for certbot before installing.
|
||||
- Install [Nginx](http://nginx.org/en/docs/install.html).
|
||||
- Create a config file called `spee.ch` in _/etc/nginx/sites-available_
|
||||
- see example: [config file](https://github.com/lbryio/spee.ch/blob/master/nginx_example_config).
|
||||
- Rename all mentions of _sub.domain.com_ with your subdomain name.
|
||||
- Run this command to link the sites-available.
|
||||
|
||||
`$ ln -s /etc/nginx/sites-available/speech /etc/nginx/sites-enabled/speech`
|
||||
|
||||
* Restart Nginx.
|
||||
- Restart Nginx.
|
||||
|
||||
`$ sudo service nginx restart`
|
||||
|
||||
* Try visiting your website.
|
||||
* If Nginx is working, you should get a **502** error because there is nothing running on **3000** yet.
|
||||
* If you get the default Nginx greeting, you have not properly configured it to serve from port **3000**.
|
||||
* You can find logs in */var/log/nginx/* too.
|
||||
* Caddy tutorial: [https://caddyserver.com/tutorial](https://caddyserver.com/tutorial)
|
||||
- Try visiting your website.
|
||||
- If Nginx is working, you should get a **502** error because there is nothing running on **3000** yet.
|
||||
- If you get the default Nginx greeting, you have not properly configured it to serve from port **3000**.
|
||||
- You can find logs in _/var/log/nginx/_ too.
|
||||
- Caddy tutorial: [https://caddyserver.com/tutorial](https://caddyserver.com/tutorial)
|
||||
|
||||
### MySql
|
||||
|
||||
* Install MySql
|
||||
* [Instructions](https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en)
|
||||
* Create user **root**.
|
||||
* Note: We are going to access **mysql** as **root** for this setup, but you may want to create a separate user in the future.
|
||||
* Keep your password somewhere handy!
|
||||
* Create a database called **lbry** and make sure you can use it.
|
||||
- Install MySql
|
||||
- [Instructions](https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en)
|
||||
- Create user **root**. \* Note: We are going to access **mysql** as **root** for this setup, but you may want to create a separate user in the future.
|
||||
- Keep your password somewhere handy!
|
||||
- Create a database called **lbry** and make sure you can use it.
|
||||
|
||||
`CREATE DATABASE lbry;`
|
||||
`CREATE DATABASE lbry;`
|
||||
|
||||
`$ USE lbry;`
|
||||
`$ USE lbry;`
|
||||
|
||||
`$ exit; (or press ‘ctl + d’)`
|
||||
`$ exit; (or press ‘ctl + d’)`
|
||||
|
||||
* Try logging into mysql.
|
||||
- Try logging into mysql.
|
||||
|
||||
`$ mysql -u username -p`
|
||||
`$ mysql -u username -p`
|
||||
|
||||
* If you are using a **LBRY** server, your **password** is the one provided for **ssh**.
|
||||
* Note: If it fails, try using `sudo`.
|
||||
- If you are using a **LBRY** server, your **password** is the one provided for **ssh**.
|
||||
- Note: If it fails, try using `sudo`.
|
||||
|
||||
##2. Install & Run the LBRY Daemon
|
||||
##2. Install & Run the LBRY Daemon
|
||||
|
||||
### Install **lbrynet**
|
||||
|
||||
_note: if you have a server from LBRY, lbrynet is already installed, you can skip to 2.4._
|
||||
|
||||
```
|
||||
$ wget --quiet -O ~/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip
|
||||
$ wget --quiet -O ~/latest_daemon.zip https://lbry.com/get/lbrynet.linux.zip
|
||||
$ unzip -o -u "~/latest_daemon.zip"
|
||||
```
|
||||
|
||||
### Start lbrynet
|
||||
|
||||
```
|
||||
$ tmux
|
||||
$ ./lbrynet-daemon
|
||||
|
@ -100,7 +108,7 @@ You should have **LBC**!
|
|||
|
||||
directions: [here](https://www.ffmpeg.org/download.html)
|
||||
|
||||
## 3. Set up Spee.ch
|
||||
## 3. Set up Spee.ch
|
||||
|
||||
### Clone the spee.ch repo
|
||||
|
||||
|
@ -127,6 +135,7 @@ $ npm run configure
|
|||
```
|
||||
|
||||
Check your site configs
|
||||
|
||||
```
|
||||
$ cd /site/config/
|
||||
$ nano siteConfig.json
|
||||
|
@ -135,6 +144,7 @@ $ nano siteConfig.json
|
|||
### Build & run
|
||||
|
||||
Run the below command to transpile, build, and start your server.
|
||||
|
||||
```
|
||||
$ npm run start
|
||||
```
|
||||
|
@ -145,17 +155,18 @@ Spee.ch should now be running !
|
|||
|
||||
Visit your site in the browser. Try publishing an image!
|
||||
|
||||
|
||||
## 4. Bonus:
|
||||
|
||||
### Install PM2 and run your server with PM2
|
||||
|
||||
Install PM2
|
||||
|
||||
```
|
||||
$ sudo npm i -g pm2
|
||||
```
|
||||
|
||||
From inside your project’s folder, start your server with PM2.
|
||||
|
||||
```
|
||||
$ pm2 start server.js
|
||||
```
|
||||
|
|
16
package-lock.json
generated
16
package-lock.json
generated
|
@ -7592,6 +7592,11 @@
|
|||
"buffer-alloc": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"isbot": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/isbot/-/isbot-2.2.1.tgz",
|
||||
"integrity": "sha512-z0idtpC0uKKKTBhd1g73GREBWhCQdnJq8U5o+8XhgPvuPiRb/vkpNreLvtoneaZX9FNxDFOU0ohEj9hTWm/tPw=="
|
||||
},
|
||||
"isemail": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
|
||||
|
@ -8552,7 +8557,7 @@
|
|||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
},
|
||||
"mississippi": {
|
||||
|
@ -13287,6 +13292,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"react-image": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-image/-/react-image-2.0.0.tgz",
|
||||
"integrity": "sha512-yWf+UAtkavJFSG1Qa4p111KncN7/a8dAOUUi5On3jjwZU1tzMXFpBnOFp04vYQr8fJmS/7ePp1OsK440WZ4fLA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"prop-types": "15.6.2"
|
||||
}
|
||||
},
|
||||
"react-input-autosize": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz",
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"image-size": "^0.6.3",
|
||||
"inquirer": "^5.2.0",
|
||||
"ip": "^1.1.5",
|
||||
"isbot": "^2.2.1",
|
||||
"lodash": "^4.17.11",
|
||||
"make-dir": "^1.3.0",
|
||||
"mime-types": "^2.1.21",
|
||||
|
@ -66,6 +67,7 @@
|
|||
"react-feather": "^1.1.4",
|
||||
"react-ga": "^2.5.3",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-image": "^2.0.0",
|
||||
"react-markdown": "^4.0.6",
|
||||
"react-redux": "^5.1.1",
|
||||
"react-router-dom": "^4.3.1",
|
||||
|
|
BIN
public/assets/img/default_thumb.jpg
Normal file
BIN
public/assets/img/default_thumb.jpg
Normal file
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
@ -1,4 +1,4 @@
|
|||
const { getClaim } = require('server/lbrynet');
|
||||
const { getClaim, resolveUri } = require('server/lbrynet');
|
||||
const { createFileRecordDataAfterGet } = require('server/models/utils/createFileRecordData.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const getClaimData = require('server/utils/getClaimData');
|
||||
|
@ -6,6 +6,7 @@ const chainquery = require('chainquery').default;
|
|||
const db = require('server/models');
|
||||
const logger = require('winston');
|
||||
const awaitFileSize = require('server/utils/awaitFileSize');
|
||||
const isBot = require('isbot');
|
||||
|
||||
/*
|
||||
|
||||
|
@ -13,7 +14,7 @@ const awaitFileSize = require('server/utils/awaitFileSize');
|
|||
|
||||
*/
|
||||
|
||||
const claimGet = async ({ ip, originalUrl, params }, res) => {
|
||||
const claimGet = async ({ ip, originalUrl, params, headers }, res) => {
|
||||
const name = params.name;
|
||||
const claimId = params.claimId;
|
||||
|
||||
|
@ -28,6 +29,16 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
|
|||
if (!claimInfo) {
|
||||
throw new Error('claim/get: resolveClaim: No matching uri found in Claim table');
|
||||
}
|
||||
if (headers && headers['user-agent'] && isBot(headers['user-agent'])) {
|
||||
let lbrynetResolveResult = await resolveUri(`${name}#${claimId}`);
|
||||
const { message, completed } = lbrynetResolveResult;
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message,
|
||||
completed: false,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
let lbrynetResult = await getClaim(`${name}#${claimId}`);
|
||||
if (!lbrynetResult) {
|
||||
throw new Error(`claim/get: getClaim Unable to Get ${name}#${claimId}`);
|
||||
|
|
|
@ -36,7 +36,7 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
|||
return db.Blocked.isNotBlocked(outpoint);
|
||||
})
|
||||
.then(() => {
|
||||
res.status(200).json({success: true, data: claimId});
|
||||
res.status(200).json({ success: true, data: claimId });
|
||||
})
|
||||
.catch(error => {
|
||||
if (error === NO_CLAIM) {
|
||||
|
@ -54,7 +54,8 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
|||
if (error === BLOCKED_CLAIM) {
|
||||
return res.status(410).json({
|
||||
success: false,
|
||||
message: 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
||||
message:
|
||||
'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.com/faq/dmca',
|
||||
});
|
||||
}
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
|
|
|
@ -118,7 +118,7 @@ const getClaimIdAndServeAsset = (
|
|||
return res.status(451).json({
|
||||
success: false,
|
||||
message:
|
||||
'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
||||
'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.com/faq/dmca',
|
||||
});
|
||||
}
|
||||
if (error === NO_FILE) {
|
||||
|
|
|
@ -75,7 +75,7 @@ function Server() {
|
|||
res
|
||||
.status(403)
|
||||
.send(
|
||||
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.io/">https://chat.lbry.io/</a>'
|
||||
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.com/">https://chat.lbry.com/</a>'
|
||||
);
|
||||
res.end();
|
||||
} else {
|
||||
|
@ -195,7 +195,7 @@ function Server() {
|
|||
'Continuing with default LBRY blocklist api endpoint. \n ' +
|
||||
'(Specify /"blockListEndpoint" : ""/ to disable.'
|
||||
);
|
||||
finalBlockListEndpoint = 'https://api.lbry.io/file/list_blocked';
|
||||
finalBlockListEndpoint = 'https://api.lbry.com/file/list_blocked';
|
||||
}
|
||||
}
|
||||
logger.info(`Peforming updates...`);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const fs = require('fs');
|
||||
|
||||
const logger = require('winston');
|
||||
const { publishing: { publishingChannelWhitelist } } = require('@config/siteConfig');
|
||||
const {
|
||||
publishing: { publishingChannelWhitelist },
|
||||
} = require('@config/siteConfig');
|
||||
const ipBanFile = './site/config/ipBan.txt';
|
||||
const forbiddenMessage = '<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.io/">https://chat.lbry.io/</a>';
|
||||
const forbiddenMessage =
|
||||
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.com/">https://chat.lbry.com/</a>';
|
||||
|
||||
let ipCounts = {};
|
||||
let blockedAddresses = [];
|
||||
|
@ -13,7 +16,7 @@ if (fs.existsSync(ipBanFile)) {
|
|||
input: require('fs').createReadStream(ipBanFile),
|
||||
});
|
||||
|
||||
lineReader.on('line', (line) => {
|
||||
lineReader.on('line', line => {
|
||||
if (line && line !== '') {
|
||||
blockedAddresses.push(line);
|
||||
}
|
||||
|
@ -30,7 +33,7 @@ const autoblockPublishMiddleware = (req, res, next) => {
|
|||
return;
|
||||
}
|
||||
|
||||
let count = ipCounts[ip] = (ipCounts[ip] || 0) + 1;
|
||||
let count = (ipCounts[ip] = (ipCounts[ip] || 0) + 1);
|
||||
|
||||
setTimeout(() => {
|
||||
if (ipCounts[ip]) {
|
||||
|
|
|
@ -3,7 +3,7 @@ const path = require('path');
|
|||
|
||||
const bundlePath = path.resolve('./public/bundle/bundle.js');
|
||||
const bundleHash = md5File.sync(bundlePath);
|
||||
const shortBundleHash = bundleHash.substring(0,4);
|
||||
const shortBundleHash = bundleHash.substring(0, 4);
|
||||
|
||||
module.exports = (helmet, html, preloadedState) => {
|
||||
// take the html and preloadedState and return the full page
|
||||
|
@ -14,6 +14,7 @@ module.exports = (helmet, html, preloadedState) => {
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="google-site-verification" content="U3240KfVplLZSRCcOHxGuDFQO6eVUXKeFsSD2WJvdLo" />
|
||||
<!--helmet-->
|
||||
${helmet.title.toString()}
|
||||
${helmet.meta.toString()}
|
||||
|
@ -27,7 +28,10 @@ module.exports = (helmet, html, preloadedState) => {
|
|||
<body>
|
||||
<div id="react-app">${html}</div>
|
||||
<script>
|
||||
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\\u003c')}
|
||||
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
|
||||
/</g,
|
||||
'\\\u003c'
|
||||
)}
|
||||
</script>
|
||||
<script src="/bundle/bundle.js?${shortBundleHash}"></script>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue