commit
790943445f
30 changed files with 522 additions and 276 deletions
|
@ -47,6 +47,7 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim
|
|||
- `./lbrynet account_balance` gets your balance (initially 0.0)
|
||||
- `./lbrynet address_list` gets addresses you can use to recieve LBC
|
||||
- [FFmpeg](https://www.ffmpeg.org/download.html)
|
||||
- [ImageMagick](https://packages.ubuntu.com/xenial/graphics/imagemagick)
|
||||
- Spee.ch (below)
|
||||
- pm2 (optional) process manager such as pm2 to run speech server.js
|
||||
- http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000
|
||||
|
@ -260,9 +261,11 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
|
|||
- retrieve the controlling `LBRY` claim:
|
||||
- https://spee.ch/`claim`
|
||||
- https://spee.ch/`claim`.`ext` (serve)
|
||||
- https://spee.ch/`claim`.`ext`&`querystring` (serve transformed)
|
||||
- retrieve a specific `LBRY` claim:
|
||||
- https://spee.ch/`claim_id`/`claim`
|
||||
- https://spee.ch/`claim_id`/`claim`.`ext` (serve)
|
||||
- https://spee.ch/`claim_id`/`claim`.`ext`&`querystring` (serve transformed)
|
||||
- retrieve all contents for the controlling `LBRY` channel
|
||||
- https://spee.ch/`@channel`
|
||||
- a specific `LBRY` channel
|
||||
|
@ -270,9 +273,15 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
|
|||
- retrieve a specific claim within the controlling `LBRY` channel
|
||||
- https://spee.ch/`@channel`/`claim`
|
||||
- https://spee.ch/`@channel`/`claim`.`ext` (serve)
|
||||
- https://spee.ch/`@channel`/`claim`.`ext`&`querystring` (serve)
|
||||
- retrieve a specific claim within a specific `LBRY` channel
|
||||
- https://spee.ch/`@channel`:`channel_id`/`claim`
|
||||
- https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve)
|
||||
- https://spee.ch/`@channel`:`channel_id`/`claim`.`ext`&`querystring` (serve)
|
||||
- `querystring` can include the following transformation values separated by `&`
|
||||
- h=`number` (defines height)
|
||||
- w=`number` (defines width)
|
||||
- t=`crop` or `stretch` (defines transformation - missing implies constrained proportions)
|
||||
|
||||
### Dependencies
|
||||
|
||||
|
|
0
changelog.md
Normal file
0
changelog.md
Normal file
|
@ -49,6 +49,10 @@
|
|||
}
|
||||
},
|
||||
"serving": {
|
||||
"dynamicFileSizing": {
|
||||
"enabled": true,
|
||||
"maxDimension": 2000
|
||||
},
|
||||
"markdownSettings": {
|
||||
"skipHtmlMain": true,
|
||||
"escapeHtmlMain": true,
|
||||
|
@ -83,10 +87,7 @@
|
|||
"code",
|
||||
"html",
|
||||
"parsedHtml"
|
||||
],
|
||||
"disallowedTypesMain": [],
|
||||
"disallowedTypesDescriptions": ["image", "html"],
|
||||
"disallowedTypesExample": ["image", "html"]
|
||||
]
|
||||
},
|
||||
"customFileExtensions": {
|
||||
"application/x-troff-man": "man",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
select {
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
background: $base-color;
|
||||
background: $background-color;
|
||||
border: 0;
|
||||
color: $text-color;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,6 @@ const ChannelSelectDropdown = ({ selectedChannel, handleSelection, loggedInChann
|
|||
id='channel-name-select'
|
||||
value={selectedChannel}
|
||||
onChange={handleSelection}>
|
||||
{ loggedInChannelName && (
|
||||
<option value={loggedInChannelName} >{loggedInChannelName}</option>
|
||||
)}
|
||||
<option value={LOGIN}>Existing</option>
|
||||
<option value={CREATE}>New</option>
|
||||
</select>
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
import React from 'react';
|
||||
import RowLabeled from '@components/RowLabeled';
|
||||
import Label from '@components/Label';
|
||||
import { LICENSES } from '@clientConstants/publish_license_urls';
|
||||
|
||||
const PublishLicenseInput = ({ handleSelect }) => {
|
||||
const PublishLicenseInput = ({ handleSelect, license }) => {
|
||||
return (
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'License:'} />
|
||||
<Label value={'License'} />
|
||||
}
|
||||
content={
|
||||
<select
|
||||
type='text'
|
||||
name='license'
|
||||
id='publish-license'
|
||||
value={license}
|
||||
onChange={handleSelect}
|
||||
>
|
||||
<option value=''>Unspecified</option>
|
||||
<option value='Public Domain'>Public Domain</option>
|
||||
<option value='Creative Commons'>Creative Commons</option>
|
||||
{
|
||||
LICENSES.map(function(item, i){
|
||||
return <option key={item + 'license key'} value={item}>{item}</option>;
|
||||
})
|
||||
}
|
||||
</select>
|
||||
}
|
||||
/>
|
||||
|
|
32
client/src/components/PublishLicenseUrlInput/index.jsx
Normal file
32
client/src/components/PublishLicenseUrlInput/index.jsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import RowLabeled from '@components/RowLabeled';
|
||||
import Label from '@components/Label';
|
||||
import { CC_LICENSES } from '@clientConstants/publish_license_urls';
|
||||
|
||||
const PublishLicenseUrlInput = ({ handleSelect, licenseUrl }) => {
|
||||
return (
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'License Url'} />
|
||||
}
|
||||
content={
|
||||
<select
|
||||
type='text'
|
||||
name='licenseUrl'
|
||||
id='publish-license-url'
|
||||
value={licenseUrl}
|
||||
onChange={handleSelect}
|
||||
>
|
||||
<option value=''>Unspecified</option>
|
||||
{
|
||||
CC_LICENSES.map(function(item, i){
|
||||
return <option key={item.url} value={item.url}>{item.value}</option>
|
||||
})
|
||||
}
|
||||
</select>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublishLicenseUrlInput;
|
33
client/src/constants/publish_license_urls.js
Normal file
33
client/src/constants/publish_license_urls.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
export const CC_LICENSES = [
|
||||
{
|
||||
value: 'CC Attr. 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by/4.0/legalcode',
|
||||
},
|
||||
{
|
||||
value: 'CC Attr-ShareAlike 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by-sa/4.0/legalcode',
|
||||
},
|
||||
{
|
||||
value: 'CC Attr-NoDerivatives 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by-nd/4.0/legalcode',
|
||||
},
|
||||
{
|
||||
value: 'CC Attr-NonComm 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by-nc/4.0/legalcode',
|
||||
},
|
||||
{
|
||||
value: 'CC Attr-NonComm-ShareAlike 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode',
|
||||
},
|
||||
{
|
||||
value: 'CC Attr-NonComm-NoDerivatives 4.0 Int',
|
||||
url: 'https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode',
|
||||
},
|
||||
];
|
||||
|
||||
export const LICENSES = ['Public Domain', 'Other', 'Copyright', 'Creative Commons'];
|
||||
|
||||
export const PUBLIC_DOMAIN = 'Public Domain';
|
||||
export const OTHER = 'other';
|
||||
export const COPYRIGHT = 'copyright';
|
||||
export const CREATIVE_COMMONS = 'Creative Commons';
|
|
@ -7,7 +7,7 @@ import AssetShareButtons from '@components/AssetShareButtons';
|
|||
import ClickToCopy from '@components/ClickToCopy';
|
||||
import siteConfig from '@config/siteConfig.json';
|
||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||
import AssetInfoFooter from '../../components/AssetInfoFooter/index';
|
||||
import AssetInfoFooter from '@components/AssetInfoFooter/index';
|
||||
import { createPermanentURI } from '@clientutils/createPermanentURI';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
|
@ -18,7 +18,20 @@ class AssetInfo extends React.Component {
|
|||
render () {
|
||||
const { editable, asset } = this.props;
|
||||
const { claimViews, claimData } = asset;
|
||||
const { channelName, claimId, channelShortId, description, name, fileExt, contentType, host, certificateId } = claimData;
|
||||
const {
|
||||
channelName,
|
||||
claimId,
|
||||
channelShortId,
|
||||
description,
|
||||
name,
|
||||
fileExt,
|
||||
contentType,
|
||||
host,
|
||||
certificateId,
|
||||
license,
|
||||
licenseUrl,
|
||||
transactionTime
|
||||
} = claimData;
|
||||
|
||||
const canonicalUrl = createCanonicalLink({ asset: { ...claimData, shortId: asset.shortId }});
|
||||
const assetCanonicalUrl = `${host}${canonicalUrl}`;
|
||||
|
@ -55,7 +68,7 @@ class AssetInfo extends React.Component {
|
|||
{editable && (
|
||||
<RowLabeled
|
||||
label={<Label value={'Edit'} />}
|
||||
content={<Link to={`/edit${canonicalUrl}`}>{name}</Link>}
|
||||
content={<Link className='link--primary' to={`/edit${canonicalUrl}`}>{name}</Link>}
|
||||
/>
|
||||
)}
|
||||
{channelName && (
|
||||
|
@ -71,19 +84,35 @@ class AssetInfo extends React.Component {
|
|||
}
|
||||
/>
|
||||
)}
|
||||
{claimViews ? (
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'Views'} />
|
||||
}
|
||||
content={
|
||||
<span className='text'>
|
||||
{claimViews}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<SpaceBetween>
|
||||
{claimViews ? (
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'Views'} />
|
||||
}
|
||||
content={
|
||||
<span className='text'>
|
||||
{claimViews}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{license && (
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'License'} />
|
||||
}
|
||||
content={
|
||||
<div className='text'>
|
||||
{licenseUrl ? (
|
||||
<a className={'link--primary'} href={licenseUrl} target={'_blank'}>{license}</a>
|
||||
) : (
|
||||
<span>{license}</span> )}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</SpaceBetween>
|
||||
<RowLabeled
|
||||
label={
|
||||
<Label value={'Share'} />
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import {connect} from 'react-redux';
|
||||
import {updateMetadata, toggleMetadataInputs} from '../../actions/publish';
|
||||
import { connect } from 'react-redux';
|
||||
import { updateMetadata, toggleMetadataInputs } from '../../actions/publish';
|
||||
import View from './view';
|
||||
|
||||
const mapStateToProps = ({ publish }) => {
|
||||
return {
|
||||
showMetadataInputs: publish.showMetadataInputs,
|
||||
description : publish.metadata.description,
|
||||
license : publish.metadata.license,
|
||||
nsfw : publish.metadata.nsfw,
|
||||
isUpdate : publish.isUpdate,
|
||||
description: publish.metadata.description,
|
||||
license: publish.metadata.license,
|
||||
licenseUrl: publish.metadata.licenseUrl,
|
||||
nsfw: publish.metadata.nsfw,
|
||||
isUpdate: publish.isUpdate,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -17,10 +18,13 @@ const mapDispatchToProps = dispatch => {
|
|||
onMetadataChange: (name, value) => {
|
||||
dispatch(updateMetadata(name, value));
|
||||
},
|
||||
onToggleMetadataInputs: (value) => {
|
||||
onToggleMetadataInputs: value => {
|
||||
dispatch(toggleMetadataInputs(value));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(View);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(View);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import PublishDescriptionInput from '@components/PublishDescriptionInput';
|
||||
import PublishLicenseInput from '@components/PublishLicenseInput';
|
||||
import PublishLicenseUrlInput from '@components/PublishLicenseUrlInput';
|
||||
import PublishNsfwInput from '@components/PublishNsfwInput';
|
||||
import ButtonSecondary from '@components/ButtonSecondary';
|
||||
import Row from '@components/Row';
|
||||
|
||||
class PublishMetadataInputs extends React.Component {
|
||||
constructor (props) {
|
||||
|
@ -25,22 +25,32 @@ class PublishMetadataInputs extends React.Component {
|
|||
const name = event.target.name;
|
||||
const selectedOption = event.target.selectedOptions[0].value;
|
||||
this.props.onMetadataChange(name, selectedOption);
|
||||
if (name === 'license' && selectedOption !== 'Creative Commons'){
|
||||
this.props.onMetadataChange('licenseUrl', '');
|
||||
}
|
||||
}
|
||||
render () {
|
||||
const { showMetadataInputs, description, isUpdate, nsfw } = this.props;
|
||||
const { showMetadataInputs, description, isUpdate, nsfw, license, licenseUrl } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{(showMetadataInputs || isUpdate) && (
|
||||
{(showMetadataInputs || isUpdate) && (
|
||||
<React.Fragment>
|
||||
<PublishDescriptionInput
|
||||
description={this.props.description}
|
||||
description={description}
|
||||
handleInput={this.handleInput}
|
||||
/>
|
||||
<PublishLicenseInput
|
||||
handleSelect={this.handleSelect}
|
||||
license={license}
|
||||
/>
|
||||
{ (this.props.license === 'Creative Commons') && (
|
||||
<PublishLicenseUrlInput
|
||||
handleSelect={this.handleSelect}
|
||||
licenseUrl={licenseUrl}
|
||||
/>
|
||||
)}
|
||||
<PublishNsfwInput
|
||||
nsfw={this.props.nsfw}
|
||||
nsfw={nsfw}
|
||||
handleInput={this.handleInput}
|
||||
/>
|
||||
</React.Fragment>
|
||||
|
|
|
@ -9,7 +9,7 @@ class EditPage extends React.Component {
|
|||
onHandleShowPageUri(match.params);
|
||||
setUpdateTrue();
|
||||
if (asset) {
|
||||
['title', 'description', 'license', 'nsfw'].forEach(meta => updateMetadata(meta, asset.claimData[meta]));
|
||||
['title', 'description', 'license', 'licenseUrl', 'nsfw'].forEach(meta => updateMetadata(meta, asset.claimData[meta]));
|
||||
}
|
||||
setHasChanged(false);
|
||||
}
|
||||
|
|
|
@ -19,40 +19,42 @@ if (siteConfig) {
|
|||
|
||||
// create initial state
|
||||
const initialState = {
|
||||
disabled : disabledConfig,
|
||||
disabledMessage : disabledMessageConfig,
|
||||
publishInChannel : false,
|
||||
selectedChannel : LOGIN,
|
||||
disabled: disabledConfig,
|
||||
disabledMessage: disabledMessageConfig,
|
||||
publishInChannel: false,
|
||||
selectedChannel: LOGIN,
|
||||
showMetadataInputs: false,
|
||||
status : {
|
||||
status : null,
|
||||
status: {
|
||||
status: null,
|
||||
message: null,
|
||||
},
|
||||
error: {
|
||||
file : null,
|
||||
url : null,
|
||||
file: null,
|
||||
url: null,
|
||||
channel: null,
|
||||
},
|
||||
file : null,
|
||||
claim : '',
|
||||
file: null,
|
||||
claim: '',
|
||||
metadata: {
|
||||
title : '',
|
||||
title: '',
|
||||
description: '',
|
||||
license : '',
|
||||
nsfw : false,
|
||||
license: '',
|
||||
licenseUrl: '',
|
||||
nsfw: false,
|
||||
},
|
||||
isUpdate : false,
|
||||
isUpdate: false,
|
||||
hasChanged: false,
|
||||
thumbnail : null,
|
||||
thumbnail: null,
|
||||
thumbnailChannel,
|
||||
thumbnailChannelId,
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
export default function(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case actions.FILE_SELECTED:
|
||||
return Object.assign({}, state.isUpdate ? state : initialState, { // note: clears to initial state
|
||||
file : action.data,
|
||||
return Object.assign({}, state.isUpdate ? state : initialState, {
|
||||
// note: clears to initial state
|
||||
file: action.data,
|
||||
hasChanged: true,
|
||||
});
|
||||
case actions.FILE_CLEAR:
|
||||
|
@ -66,13 +68,13 @@ export default function (state = initialState, action) {
|
|||
});
|
||||
case actions.CLAIM_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
claim : action.data,
|
||||
claim: action.data,
|
||||
hasChanged: true,
|
||||
});
|
||||
case actions.SET_PUBLISH_IN_CHANNEL:
|
||||
return Object.assign({}, state, {
|
||||
publishInChannel: action.channel,
|
||||
hasChanged : true,
|
||||
hasChanged: true,
|
||||
});
|
||||
case actions.PUBLISH_STATUS_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
|
@ -96,7 +98,7 @@ export default function (state = initialState, action) {
|
|||
case actions.THUMBNAIL_NEW:
|
||||
return {
|
||||
...state,
|
||||
thumbnail : action.data,
|
||||
thumbnail: action.data,
|
||||
hasChanged: true,
|
||||
};
|
||||
case actions.SET_UPDATE_TRUE:
|
||||
|
@ -112,4 +114,4 @@ export default function (state = initialState, action) {
|
|||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
export const createPublishMetadata = (claim, { type }, { title, description, license, nsfw }, publishInChannel, selectedChannel) => {
|
||||
export const createPublishMetadata = (
|
||||
claim,
|
||||
{ type },
|
||||
{ title, description, license, licenseUrl, nsfw },
|
||||
publishInChannel,
|
||||
selectedChannel
|
||||
) => {
|
||||
let metadata = {
|
||||
name: claim,
|
||||
title,
|
||||
description,
|
||||
license,
|
||||
licenseUrl,
|
||||
nsfw,
|
||||
type,
|
||||
};
|
||||
|
|
|
@ -26,7 +26,6 @@ PUBLISHING:
|
|||
|
||||
"primaryClaimAddress": null, - generally supplied by your lbrynet sdk
|
||||
"uploadDirectory": "/home/lbry/Uploads", - lbrynet sdk will know your uploads are here
|
||||
"lbrynetHome": "/home/lbry",
|
||||
"thumbnailChannel": null, - when publishing non-image content, thumbnails will go here.
|
||||
"thumbnailChannelId": null,
|
||||
"additionalClaimAddresses": [],
|
||||
|
@ -50,48 +49,52 @@ PUBLISHING:
|
|||
"application/octet-stream": 50000000
|
||||
}
|
||||
}
|
||||
|
||||
SERVING:
|
||||
|
||||
"markdownSettings": {
|
||||
"skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~
|
||||
"escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly
|
||||
"skipHtmlDescriptions": true, - as above, for descriptions
|
||||
"escapeHtmlDescriptions": true, - as above, for descriptions
|
||||
"allowedTypesMain": [], - markdown rendered as main content
|
||||
"allowedTypesDescriptions": [], - markdown rendered in description in content details
|
||||
"allowedTypesExample": [ - here are examples of allowed types
|
||||
"see react-markdown docs", `https://github.com/rexxars/react-markdown`
|
||||
"root",
|
||||
"text",
|
||||
"break",
|
||||
"paragraph",
|
||||
"emphasis",
|
||||
"strong",
|
||||
"thematicBreak",
|
||||
"blockquote",
|
||||
"delete",
|
||||
"link",
|
||||
"image", - you may not have a lot of control over how these are rendered
|
||||
"linkReference",
|
||||
"imageReference",
|
||||
"table",
|
||||
"tableHead",
|
||||
"tableBody",
|
||||
"tableRow",
|
||||
"tableCell",
|
||||
"list",
|
||||
"listItem",
|
||||
"heading",
|
||||
"inlineCode",
|
||||
"code",
|
||||
"html", - potentially DANGEROUS, intended for `serveOnlyApproved = true` environments, includes iframes, divs.
|
||||
"parsedHtml"
|
||||
],
|
||||
},
|
||||
"customFileExtensions": { - suggest a file extension for experimental content types you may be publishing
|
||||
"application/example-type": "example"
|
||||
}
|
||||
SERVING:
|
||||
|
||||
"dynamicFileSizing": {
|
||||
"enabled": false, - if you choose to allow your instance to serve transform images
|
||||
"maxDimension": 2000 - the maximum size you allow transform to scale
|
||||
},
|
||||
"markdownSettings": {
|
||||
"skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~
|
||||
"escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly
|
||||
"skipHtmlDescriptions": true, - as above, for descriptions
|
||||
"escapeHtmlDescriptions": true, - as above, for descriptions
|
||||
"allowedTypesMain": [], - markdown rendered as main content
|
||||
"allowedTypesDescriptions": [], - markdown rendered in description in content details
|
||||
"allowedTypesExample": [ - here are examples of allowed types
|
||||
"see react-markdown docs", `https://github.com/rexxars/react-markdown`
|
||||
"root",
|
||||
"text",
|
||||
"break",
|
||||
"paragraph",
|
||||
"emphasis",
|
||||
"strong",
|
||||
"thematicBreak",
|
||||
"blockquote",
|
||||
"delete",
|
||||
"link",
|
||||
"image", - you may not have a lot of control over how these are rendered
|
||||
"linkReference",
|
||||
"imageReference",
|
||||
"table",
|
||||
"tableHead",
|
||||
"tableBody",
|
||||
"tableRow",
|
||||
"tableCell",
|
||||
"list",
|
||||
"listItem",
|
||||
"heading",
|
||||
"inlineCode",
|
||||
"code",
|
||||
"html", - potentially DANGEROUS, intended for `serveOnlyApproved = true` environments, includes iframes, divs.
|
||||
"parsedHtml"
|
||||
],
|
||||
},
|
||||
"customFileExtensions": { - suggest a file extension for experimental content types you may be publishing
|
||||
"application/example-type": "example"
|
||||
}
|
||||
|
||||
STARTUP:
|
||||
|
||||
|
|
141
package-lock.json
generated
141
package-lock.json
generated
|
@ -1522,20 +1522,11 @@
|
|||
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
|
||||
"dev": true
|
||||
},
|
||||
"align-text": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
|
||||
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2",
|
||||
"longest": "^1.0.1",
|
||||
"repeat-string": "^1.5.2"
|
||||
}
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-align": {
|
||||
"version": "2.0.0",
|
||||
|
@ -1765,9 +1756,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
|
||||
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
},
|
||||
"async-each": {
|
||||
"version": "1.0.1",
|
||||
|
@ -3015,12 +3009,6 @@
|
|||
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
|
||||
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
|
||||
"optional": true
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
|
@ -3088,16 +3076,6 @@
|
|||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"center-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
||||
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"align-text": "^0.1.3",
|
||||
"lazy-cache": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
|
||||
|
@ -3341,25 +3319,6 @@
|
|||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
|
||||
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
|
||||
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"center-align": "^0.1.1",
|
||||
"right-align": "^0.1.1",
|
||||
"wordwrap": "0.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
|
||||
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"clone-deep": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
|
||||
|
@ -6544,14 +6503,21 @@
|
|||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
|
||||
"integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz",
|
||||
"integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==",
|
||||
"requires": {
|
||||
"async": "^1.4.0",
|
||||
"async": "^2.5.0",
|
||||
"optimist": "^0.6.1",
|
||||
"source-map": "^0.4.4",
|
||||
"uglify-js": "^2.6"
|
||||
"source-map": "^0.6.1",
|
||||
"uglify-js": "^3.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
|
@ -7807,6 +7773,7 @@
|
|||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
|
@ -7820,12 +7787,6 @@
|
|||
"package-json": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
|
||||
"optional": true
|
||||
},
|
||||
"lcid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
||||
|
@ -8205,11 +8166,6 @@
|
|||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
|
@ -8596,7 +8552,7 @@
|
|||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
},
|
||||
"mississippi": {
|
||||
|
@ -13870,15 +13826,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"right-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
|
||||
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"align-text": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
|
@ -14746,6 +14693,7 @@
|
|||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"amdefine": ">=0.0.4"
|
||||
}
|
||||
|
@ -15651,30 +15599,23 @@
|
|||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "2.8.29",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
||||
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
|
||||
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"source-map": "~0.5.1",
|
||||
"uglify-to-browserify": "~1.0.0",
|
||||
"yargs": "~3.10.0"
|
||||
"commander": "~2.17.1",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"uglify-to-browserify": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
|
||||
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
|
||||
"optional": true
|
||||
},
|
||||
"uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
|
@ -16716,12 +16657,6 @@
|
|||
"string-width": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"window-size": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
|
||||
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
|
||||
"optional": true
|
||||
},
|
||||
"winston": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz",
|
||||
|
@ -16881,18 +16816,6 @@
|
|||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"camelcase": "^1.0.2",
|
||||
"cliui": "^2.1.0",
|
||||
"decamelize": "^1.0.0",
|
||||
"window-size": "0.1.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
|
||||
|
|
|
@ -6,7 +6,7 @@ const {
|
|||
|
||||
const getterMethods = {
|
||||
generated_extension() {
|
||||
logger.info('trying to generate extension', this.content_type);
|
||||
logger.debug('trying to generate extension', this.content_type);
|
||||
if (customFileExtensions.hasOwnProperty(this.content_type)) {
|
||||
return customFileExtensions[this.content_type];
|
||||
} else {
|
||||
|
@ -136,6 +136,14 @@ export default (sequelize, { BOOLEAN, DATE, DECIMAL, ENUM, INTEGER, STRING, TEXT
|
|||
type: STRING,
|
||||
set() {},
|
||||
},
|
||||
license: {
|
||||
type: STRING,
|
||||
set() {},
|
||||
},
|
||||
license_url: {
|
||||
type: STRING,
|
||||
set() {},
|
||||
},
|
||||
},
|
||||
{
|
||||
freezeTableName: true,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
const chainquery = require('chainquery').default;
|
||||
const logger = require('winston');
|
||||
const getClaimData = require('server/utils/getClaimData');
|
||||
const { returnPaginatedChannelClaims } = require('./channelPagination.js');
|
||||
|
||||
const getChannelClaims = async (channelName, channelLongId, page) => {
|
||||
logger.debug(`getChannelClaims: ${channelName}, ${channelLongId}, ${page}`);
|
||||
let channelShortId = await chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
||||
channelLongId,
|
||||
channelName
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const { getClaim } = require('../../../../lbrynet');
|
||||
const { createFileRecordDataAfterGet } = require('../../../../models/utils/createFileRecordData.js');
|
||||
const { getClaim } = require('server/lbrynet');
|
||||
const { createFileRecordDataAfterGet } = require('server/models/utils/createFileRecordData.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const getClaimData = require('server/utils/getClaimData');
|
||||
const chainquery = require('chainquery').default;
|
||||
const db = require('../../../../models');
|
||||
const waitOn = require('wait-on');
|
||||
const db = require('server/models');
|
||||
const logger = require('winston');
|
||||
const awaitFileSize = require('server/utils/awaitFileSize');
|
||||
|
||||
/*
|
||||
|
||||
|
@ -36,11 +36,11 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
|
|||
if (!claimData) {
|
||||
throw new Error('claim/get: getClaimData failed to get file blobs');
|
||||
}
|
||||
await waitOn({
|
||||
resources: [ lbrynetResult.download_path ],
|
||||
timeout : 10000, // 10 seconds
|
||||
window : 500,
|
||||
});
|
||||
const fileReady = await awaitFileSize(lbrynetResult.outpoint, 10000000, 250, 10000);
|
||||
|
||||
if (fileReady !== 'ready') {
|
||||
throw new Error('claim/get: failed to get file after 10 seconds');
|
||||
}
|
||||
const fileData = await createFileRecordDataAfterGet(claimData, lbrynetResult);
|
||||
if (!fileData) {
|
||||
throw new Error('claim/get: createFileRecordDataAfterGet failed to create file in time');
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
const logger = require('winston');
|
||||
const { details, publishing } = require('@config/siteConfig');
|
||||
const createPublishParams = (filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId) => {
|
||||
const createPublishParams = (
|
||||
filePath,
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
license,
|
||||
licenseUrl,
|
||||
nsfw,
|
||||
thumbnail,
|
||||
channelName,
|
||||
channelClaimId
|
||||
) => {
|
||||
// provide defaults for title
|
||||
if (title === null || title.trim() === '') {
|
||||
title = name;
|
||||
|
@ -11,19 +22,24 @@ const createPublishParams = (filePath, name, title, description, license, nsfw,
|
|||
}
|
||||
// provide default for license
|
||||
if (license === null || license.trim() === '') {
|
||||
license = ''; // default to empty string
|
||||
license = ''; // default to empty string
|
||||
}
|
||||
// provide default for licenseUrl
|
||||
if (licenseUrl === null || licenseUrl.trim() === '') {
|
||||
licenseUrl = ''; // default to empty string
|
||||
}
|
||||
// create the basic publish params
|
||||
const publishParams = {
|
||||
name,
|
||||
file_path: filePath,
|
||||
bid : publishing.fileClaimBidAmount,
|
||||
metadata : {
|
||||
bid: publishing.fileClaimBidAmount,
|
||||
metadata: {
|
||||
description,
|
||||
title,
|
||||
author : details.title,
|
||||
author: details.title,
|
||||
language: 'en',
|
||||
license,
|
||||
licenseUrl,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
const logger = require('winston');
|
||||
const { details, publishing } = require('@config/siteConfig');
|
||||
|
||||
const createThumbnailPublishParams = (thumbnailFilePath, claimName, license, nsfw) => {
|
||||
const createThumbnailPublishParams = (thumbnailFilePath, claimName, license, licenseUrl, nsfw) => {
|
||||
if (!thumbnailFilePath) {
|
||||
return;
|
||||
}
|
||||
logger.debug(`Creating Thumbnail Publish Parameters`);
|
||||
// create the publish params
|
||||
return {
|
||||
name : `${claimName}-thumb`,
|
||||
name: `${claimName}-thumb`,
|
||||
file_path: thumbnailFilePath,
|
||||
bid : publishing.fileClaimBidAmount,
|
||||
metadata : {
|
||||
title : `${claimName} thumbnail`,
|
||||
bid: publishing.fileClaimBidAmount,
|
||||
metadata: {
|
||||
title: `${claimName} thumbnail`,
|
||||
description: `a thumbnail for ${claimName}`,
|
||||
author : details.title,
|
||||
language : 'en',
|
||||
author: details.title,
|
||||
language: 'en',
|
||||
license,
|
||||
licenseUrl,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
channel_name : publishing.thumbnailChannel,
|
||||
channel_id : publishing.thumbnailChannelId,
|
||||
channel_name: publishing.thumbnailChannel,
|
||||
channel_id: publishing.thumbnailChannelId,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const { details: { host }, publishing: { disabled, disabledMessage } } = require('@config/siteConfig');
|
||||
const {
|
||||
details: { host },
|
||||
publishing: { disabled, disabledMessage },
|
||||
} = require('@config/siteConfig');
|
||||
|
||||
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||
const { sendGATimingEvent } = require('server/utils/googleAnalytics.js');
|
||||
const isApprovedChannel = require('@globalutils/isApprovedChannel');
|
||||
const { publishing: { publishOnlyApproved, approvedChannels } } = require('@config/siteConfig');
|
||||
const {
|
||||
publishing: { publishOnlyApproved, approvedChannels },
|
||||
} = require('@config/siteConfig');
|
||||
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
|
@ -55,6 +60,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
fileType,
|
||||
gaStartTime,
|
||||
license,
|
||||
licenseUrl,
|
||||
name,
|
||||
nsfw,
|
||||
thumbnail,
|
||||
|
@ -69,18 +75,34 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
// validate the body and files of the request
|
||||
try {
|
||||
// validateApiPublishRequest(body, files);
|
||||
({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
|
||||
({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
|
||||
({channelName, channelId, channelPassword} = body);
|
||||
({
|
||||
name,
|
||||
nsfw,
|
||||
license,
|
||||
licenseUrl,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
} = parsePublishApiRequestBody(body));
|
||||
({
|
||||
fileName,
|
||||
filePath,
|
||||
fileExtension,
|
||||
fileType,
|
||||
thumbnailFileName,
|
||||
thumbnailFilePath,
|
||||
thumbnailFileType,
|
||||
} = parsePublishApiRequestFiles(files));
|
||||
({ channelName, channelId, channelPassword } = body);
|
||||
} catch (error) {
|
||||
return res.status(400).json({success: false, message: error.message});
|
||||
return res.status(400).json({ success: false, message: error.message });
|
||||
}
|
||||
// check channel authorization
|
||||
authenticateUser(channelName, channelId, channelPassword, user)
|
||||
.then(({ channelName, channelClaimId }) => {
|
||||
if (publishOnlyApproved && !isApprovedChannel({ longId: channelClaimId }, approvedChannels)) {
|
||||
const error = {
|
||||
name : UNAPPROVED_CHANNEL,
|
||||
name: UNAPPROVED_CHANNEL,
|
||||
message: 'This spee.ch instance only allows publishing to approved channels',
|
||||
};
|
||||
throw error;
|
||||
|
@ -88,14 +110,25 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
|
||||
return Promise.all([
|
||||
checkClaimAvailability(name),
|
||||
createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId),
|
||||
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
|
||||
createPublishParams(
|
||||
filePath,
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
license,
|
||||
licenseUrl,
|
||||
nsfw,
|
||||
thumbnail,
|
||||
channelName,
|
||||
channelClaimId
|
||||
),
|
||||
createThumbnailPublishParams(thumbnailFilePath, name, license, licenseUrl, nsfw),
|
||||
]);
|
||||
})
|
||||
.then(([ claimAvailable, publishParams, thumbnailPublishParams ]) => {
|
||||
.then(([claimAvailable, publishParams, thumbnailPublishParams]) => {
|
||||
if (!claimAvailable) {
|
||||
const error = {
|
||||
name : CLAIM_TAKEN,
|
||||
name: CLAIM_TAKEN,
|
||||
message: 'That claim name is already taken',
|
||||
};
|
||||
throw error;
|
||||
|
@ -110,14 +143,20 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
.then(publishResults => {
|
||||
logger.info('Publish success >', publishResults);
|
||||
claimData = publishResults;
|
||||
({claimId} = claimData);
|
||||
({ claimId } = claimData);
|
||||
|
||||
if (channelName) {
|
||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimData.certificateId, channelName);
|
||||
logger.info(`api/claim/publish: claimData.certificateId ${claimData.certificateId}`);
|
||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
||||
claimData.certificateId,
|
||||
channelName
|
||||
);
|
||||
} else {
|
||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimId, name, claimData).catch(() => {
|
||||
return claimId.slice(0, 1);
|
||||
});
|
||||
return chainquery.claim.queries
|
||||
.getShortClaimIdFromLongClaimId(claimId, name, claimData)
|
||||
.catch(() => {
|
||||
return claimId.slice(0, 1);
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(shortId => {
|
||||
|
@ -131,13 +170,13 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'publish completed successfully',
|
||||
data : {
|
||||
data: {
|
||||
name,
|
||||
claimId,
|
||||
url : `${host}${canonicalUrl}`, // for backwards compatability with app
|
||||
showUrl : `${host}${canonicalUrl}`,
|
||||
url: `${host}${canonicalUrl}`, // for backwards compatability with app
|
||||
showUrl: `${host}${canonicalUrl}`,
|
||||
serveUrl: `${host}${canonicalUrl}${fileExtension}`,
|
||||
pushTo : canonicalUrl,
|
||||
pushTo: canonicalUrl,
|
||||
claimData,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
const parsePublishApiRequestBody = ({name, nsfw, license, title, description, thumbnail}) => {
|
||||
const parsePublishApiRequestBody = ({
|
||||
name,
|
||||
nsfw,
|
||||
license,
|
||||
licenseUrl,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
}) => {
|
||||
// validate name
|
||||
if (!name) {
|
||||
throw new Error('no name field found in request');
|
||||
}
|
||||
const invalidNameCharacters = /[^A-Za-z0-9,-]/.exec(name);
|
||||
if (invalidNameCharacters) {
|
||||
throw new Error('The claim name you provided is not allowed. Only the following characters are allowed: A-Z, a-z, 0-9, and "-"');
|
||||
throw new Error(
|
||||
'The claim name you provided is not allowed. Only the following characters are allowed: A-Z, a-z, 0-9, and "-"'
|
||||
);
|
||||
}
|
||||
// optional parameters
|
||||
nsfw = (nsfw === 'true');
|
||||
nsfw = nsfw === 'true';
|
||||
license = license || null;
|
||||
licenseUrl = licenseUrl || null;
|
||||
title = title || null;
|
||||
description = description || null;
|
||||
thumbnail = thumbnail || null;
|
||||
|
@ -18,6 +29,7 @@ const parsePublishApiRequestBody = ({name, nsfw, license, title, description, th
|
|||
name,
|
||||
nsfw,
|
||||
license,
|
||||
licenseUrl,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
|
|
|
@ -19,10 +19,11 @@ const createCanonicalLink = require('@globalutils/createCanonicalLink');
|
|||
route to update a claim through the daemon
|
||||
*/
|
||||
|
||||
const updateMetadata = ({ nsfw, license, title, description }) => {
|
||||
const updateMetadata = ({ nsfw, license, licenseUrl, title, description }) => {
|
||||
const update = {};
|
||||
if (nsfw) update['nsfw'] = nsfw;
|
||||
if (license) update['license'] = license;
|
||||
if (licenseUrl) update['licenseUrl'] = licenseUrl;
|
||||
if (title) update['title'] = title;
|
||||
if (description) update['description'] = description;
|
||||
return update;
|
||||
|
@ -65,6 +66,7 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
thumbnail,
|
||||
fileExtension,
|
||||
license,
|
||||
licenseUrl,
|
||||
name,
|
||||
nsfw,
|
||||
thumbnailFileName,
|
||||
|
@ -79,7 +81,15 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
gaStartTime = Date.now();
|
||||
|
||||
try {
|
||||
({ name, nsfw, license, title, description, thumbnail } = parsePublishApiRequestBody(body));
|
||||
({
|
||||
name,
|
||||
nsfw,
|
||||
license,
|
||||
licenseUrl,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
} = parsePublishApiRequestBody(body));
|
||||
({
|
||||
fileName,
|
||||
filePath,
|
||||
|
@ -127,10 +137,11 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
|||
description: claimRecord.description,
|
||||
nsfw: claimRecord.nsfw,
|
||||
license: claimRecord.license,
|
||||
licenseUrl: claimRecord.license_url,
|
||||
language: 'en',
|
||||
author: details.title,
|
||||
},
|
||||
updateMetadata({ title, description, nsfw, license })
|
||||
updateMetadata({ title, description, nsfw, license, licenseUrl })
|
||||
);
|
||||
const publishParams = {
|
||||
name,
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
const logger = require('winston');
|
||||
const transformImage = require('./transformImage');
|
||||
|
||||
const isValidQueryObject = require('server/utils/isValidQueryObj');
|
||||
const {
|
||||
serving: { dynamicFileSizing },
|
||||
} = require('@config/siteConfig');
|
||||
const { enabled: dynamicEnabled } = dynamicFileSizing;
|
||||
|
||||
const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
|
||||
const queryObject = {};
|
||||
// TODO: replace quick/dirty try catch with better practice
|
||||
|
@ -21,7 +28,10 @@ const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
|
|||
|
||||
let mediaType = fileType ? fileType.substr(0, fileType.indexOf('/')) : '';
|
||||
const transform =
|
||||
mediaType === 'image' && queryObject.hasOwnProperty('h') && queryObject.hasOwnProperty('w');
|
||||
mediaType === 'image' &&
|
||||
queryObject.hasOwnProperty('h') &&
|
||||
queryObject.hasOwnProperty('w') &&
|
||||
dynamicEnabled;
|
||||
|
||||
const sendFileOptions = {
|
||||
headers: {
|
||||
|
@ -32,14 +42,26 @@ const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
|
|||
},
|
||||
};
|
||||
logger.debug(`fileOptions for ${filePath}:`, sendFileOptions);
|
||||
if (transform) {
|
||||
logger.debug(`transforming and sending file`);
|
||||
try {
|
||||
if (transform) {
|
||||
if (!isValidQueryObject(queryObject)) {
|
||||
logger.debug(`Unacceptable querystring`, { queryObject });
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Querystring may not have dimensions greater than 2000',
|
||||
});
|
||||
res.end();
|
||||
}
|
||||
logger.debug(`transforming and sending file`);
|
||||
|
||||
let xformed = await transformImage(filePath, queryObject);
|
||||
res.status(200).set(sendFileOptions.headers);
|
||||
res.end(xformed, 'binary');
|
||||
} else {
|
||||
res.status(200).sendFile(filePath, sendFileOptions);
|
||||
let xformed = await transformImage(filePath, queryObject);
|
||||
res.status(200).set(sendFileOptions.headers);
|
||||
res.end(xformed, 'binary');
|
||||
} else {
|
||||
res.status(200).sendFile(filePath, sendFileOptions);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.debug(e);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,26 @@ module.exports = {
|
|||
});
|
||||
});
|
||||
},
|
||||
getFileListFileByOutpoint(outpoint) {
|
||||
logger.debug(`lbryApi >> Getting File_List for "${outpoint}"`);
|
||||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbrynetUri, {
|
||||
method: 'file_list',
|
||||
params: {
|
||||
outpoint,
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
sendGATimingEvent('lbrynet', 'getFileList', 'FILE_LIST', gaStartTime, Date.now());
|
||||
handleLbrynetResponse(response, resolve, reject);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
async abandonClaim({ claimId }) {
|
||||
logger.debug(`lbryApi >> Abandon claim "${claimId}"`);
|
||||
const gaStartTime = Date.now();
|
||||
|
|
30
server/utils/awaitFileSize.js
Normal file
30
server/utils/awaitFileSize.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const { getFileListFileByOutpoint } = require('server/lbrynet');
|
||||
const logger = require('winston');
|
||||
|
||||
function delay(t) {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, t);
|
||||
});
|
||||
}
|
||||
|
||||
const awaitFileSize = (outpoint, size, interval, timeout) => {
|
||||
logger.debug('awaitFileSize');
|
||||
let start = Date.now();
|
||||
function checkFileList() {
|
||||
logger.debug('checkFileList');
|
||||
return getFileListFileByOutpoint(outpoint).then(result => {
|
||||
logger.debug('File List Result', result);
|
||||
if (result[0]['completed'] === true || result[0]['written_bytes'] > size) {
|
||||
logger.debug('FILE READY');
|
||||
return 'ready';
|
||||
} else if (timeout !== 0 && Date.now() - start > timeout) {
|
||||
throw new Error('Timeout on awaitFileSize');
|
||||
} else {
|
||||
return delay(interval).then(checkFileList);
|
||||
}
|
||||
});
|
||||
}
|
||||
return checkFileList();
|
||||
};
|
||||
|
||||
module.exports = awaitFileSize;
|
|
@ -59,5 +59,8 @@ module.exports = async (data, chName = null, chShortId = null) => {
|
|||
host,
|
||||
pending: Boolean(dataVals.height === 0),
|
||||
blocked: blocked,
|
||||
license: dataVals.license,
|
||||
licenseUrl: dataVals.license_url,
|
||||
transactionTime: dataVals.transaction_time,
|
||||
};
|
||||
};
|
||||
|
|
24
server/utils/isValidQueryObj.js
Normal file
24
server/utils/isValidQueryObj.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const {
|
||||
serving: { dynamicFileSizing },
|
||||
} = require('@config/siteConfig');
|
||||
const { maxDimension } = dynamicFileSizing;
|
||||
|
||||
const isValidQueryObj = queryObj => {
|
||||
let {
|
||||
h: cHeight = null,
|
||||
w: cWidth = null,
|
||||
t: transform = null,
|
||||
x: xOrigin = null,
|
||||
y: yOrigin = null,
|
||||
} = queryObj;
|
||||
|
||||
return (
|
||||
((cHeight <= maxDimension && cHeight > 0) || cHeight === null) &&
|
||||
((cWidth <= maxDimension && cWidth > 0) || cWidth === null) &&
|
||||
(transform === null || transform === 'crop' || transform === 'stretch') &&
|
||||
((xOrigin <= maxDimension && xOrigin >= 0) || xOrigin === null) &&
|
||||
((yOrigin <= maxDimension && yOrigin >= 0) || yOrigin === null)
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = isValidQueryObj;
|
|
@ -39,6 +39,9 @@ module.exports = () => {
|
|||
moduleAliases['@clientutils'] = resolve(`${DEFAULT_ROOT}/utils`);
|
||||
// moduleAliases['@serverutils'] = resolve('server/utils');
|
||||
|
||||
// aliases for constants
|
||||
moduleAliases['@clientConstants'] = resolve(`${DEFAULT_ROOT}/constants`);
|
||||
|
||||
// create specific aliases for locally defined components in the following folders
|
||||
moduleAliases = addAliasesForCustomComponentFolder('containers', moduleAliases);
|
||||
moduleAliases = addAliasesForCustomComponentFolder('components', moduleAliases);
|
||||
|
@ -53,7 +56,6 @@ module.exports = () => {
|
|||
moduleAliases['@sagas'] = resolve(`${DEFAULT_ROOT}/sagas`);
|
||||
moduleAliases['@app'] = resolve(`${DEFAULT_ROOT}/app.js`);
|
||||
|
||||
|
||||
// return finished aliases
|
||||
return moduleAliases;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue