diff --git a/README.md b/README.md
index 1a90580a..6d6f43bb 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 00000000..e69de29b
diff --git a/cli/defaults/siteConfig.json b/cli/defaults/siteConfig.json
index b7ff5337..e8af29a7 100644
--- a/cli/defaults/siteConfig.json
+++ b/cli/defaults/siteConfig.json
@@ -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",
diff --git a/client/scss/_select.scss b/client/scss/_select.scss
index 382adf4c..b095c7b3 100644
--- a/client/scss/_select.scss
+++ b/client/scss/_select.scss
@@ -1,6 +1,7 @@
select {
margin: 0;
display: inline-block;
- background: $base-color;
+ background: $background-color;
border: 0;
+ color: $text-color;
}
diff --git a/client/src/components/ChannelSelectDropdown/index.jsx b/client/src/components/ChannelSelectDropdown/index.jsx
index 2079c05c..ae4b1211 100644
--- a/client/src/components/ChannelSelectDropdown/index.jsx
+++ b/client/src/components/ChannelSelectDropdown/index.jsx
@@ -7,9 +7,6 @@ const ChannelSelectDropdown = ({ selectedChannel, handleSelection, loggedInChann
id='channel-name-select'
value={selectedChannel}
onChange={handleSelection}>
- { loggedInChannelName && (
-
- )}
diff --git a/client/src/components/PublishLicenseInput/index.jsx b/client/src/components/PublishLicenseInput/index.jsx
index af827ec8..4ddf4f07 100644
--- a/client/src/components/PublishLicenseInput/index.jsx
+++ b/client/src/components/PublishLicenseInput/index.jsx
@@ -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 (
+
}
content={
}
/>
diff --git a/client/src/components/PublishLicenseUrlInput/index.jsx b/client/src/components/PublishLicenseUrlInput/index.jsx
new file mode 100644
index 00000000..8b57347e
--- /dev/null
+++ b/client/src/components/PublishLicenseUrlInput/index.jsx
@@ -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 (
+
+ }
+ content={
+
+ }
+ />
+ );
+};
+
+export default PublishLicenseUrlInput;
diff --git a/client/src/constants/publish_license_urls.js b/client/src/constants/publish_license_urls.js
new file mode 100644
index 00000000..06f1db9f
--- /dev/null
+++ b/client/src/constants/publish_license_urls.js
@@ -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';
diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx
index 49dfeedc..79fd1436 100644
--- a/client/src/containers/AssetInfo/view.jsx
+++ b/client/src/containers/AssetInfo/view.jsx
@@ -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 && (
}
- content={{name}}
+ content={{name}}
/>
)}
{channelName && (
@@ -71,19 +84,35 @@ class AssetInfo extends React.Component {
}
/>
)}
- {claimViews ? (
-
- }
- content={
-
- {claimViews}
-
- }
- />
- ) : null}
-
+
+ {claimViews ? (
+
+ }
+ content={
+
+ {claimViews}
+
+ }
+ />
+ ) : null}
+ {license && (
+
+ }
+ content={
+
+ {licenseUrl ? (
+
{license}
+ ) : (
+
{license} )}
+
+ }
+ />
+ )}
+
diff --git a/client/src/containers/PublishMetadataInputs/index.js b/client/src/containers/PublishMetadataInputs/index.js
index 1c5b462a..7e31ce30 100644
--- a/client/src/containers/PublishMetadataInputs/index.js
+++ b/client/src/containers/PublishMetadataInputs/index.js
@@ -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);
diff --git a/client/src/containers/PublishMetadataInputs/view.jsx b/client/src/containers/PublishMetadataInputs/view.jsx
index 2234e2ad..07e4d8d1 100644
--- a/client/src/containers/PublishMetadataInputs/view.jsx
+++ b/client/src/containers/PublishMetadataInputs/view.jsx
@@ -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 (
- {(showMetadataInputs || isUpdate) && (
+ {(showMetadataInputs || isUpdate) && (
+ { (this.props.license === 'Creative Commons') && (
+
+ )}
diff --git a/client/src/pages/EditPage/view.jsx b/client/src/pages/EditPage/view.jsx
index 60b07900..eab64176 100644
--- a/client/src/pages/EditPage/view.jsx
+++ b/client/src/pages/EditPage/view.jsx
@@ -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);
}
diff --git a/client/src/reducers/publish.js b/client/src/reducers/publish.js
index 25171405..58a37aa4 100644
--- a/client/src/reducers/publish.js
+++ b/client/src/reducers/publish.js
@@ -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;
}
-};
+}
diff --git a/client/src/utils/publish.js b/client/src/utils/publish.js
index 00ac2240..4de574cf 100644
--- a/client/src/utils/publish.js
+++ b/client/src/utils/publish.js
@@ -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,
};
diff --git a/docs/settings.md b/docs/settings.md
index 1bf06aa3..57c3341b 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -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:
diff --git a/package-lock.json b/package-lock.json
index c8dace28..d2dc03e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/server/chainquery/models/ClaimModel.js b/server/chainquery/models/ClaimModel.js
index 4fcc1af0..4157ab67 100644
--- a/server/chainquery/models/ClaimModel.js
+++ b/server/chainquery/models/ClaimModel.js
@@ -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,
diff --git a/server/controllers/api/channel/claims/getChannelClaims.js b/server/controllers/api/channel/claims/getChannelClaims.js
index 921c1f2e..8b7eee60 100644
--- a/server/controllers/api/channel/claims/getChannelClaims.js
+++ b/server/controllers/api/channel/claims/getChannelClaims.js
@@ -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
diff --git a/server/controllers/api/claim/get/index.js b/server/controllers/api/claim/get/index.js
index 94914810..3a0008b0 100644
--- a/server/controllers/api/claim/get/index.js
+++ b/server/controllers/api/claim/get/index.js
@@ -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');
diff --git a/server/controllers/api/claim/publish/createPublishParams.js b/server/controllers/api/claim/publish/createPublishParams.js
index 364e831a..0a51cba8 100644
--- a/server/controllers/api/claim/publish/createPublishParams.js
+++ b/server/controllers/api/claim/publish/createPublishParams.js
@@ -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,
diff --git a/server/controllers/api/claim/publish/createThumbnailPublishParams.js b/server/controllers/api/claim/publish/createThumbnailPublishParams.js
index 576ddc73..a848aab5 100644
--- a/server/controllers/api/claim/publish/createThumbnailPublishParams.js
+++ b/server/controllers/api/claim/publish/createThumbnailPublishParams.js
@@ -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,
};
};
diff --git a/server/controllers/api/claim/publish/index.js b/server/controllers/api/claim/publish/index.js
index b795bde0..f08bf76b 100644
--- a/server/controllers/api/claim/publish/index.js
+++ b/server/controllers/api/claim/publish/index.js
@@ -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,
},
});
diff --git a/server/controllers/api/claim/publish/parsePublishApiRequestBody.js b/server/controllers/api/claim/publish/parsePublishApiRequestBody.js
index e417e0a9..f98c3369 100644
--- a/server/controllers/api/claim/publish/parsePublishApiRequestBody.js
+++ b/server/controllers/api/claim/publish/parsePublishApiRequestBody.js
@@ -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,
diff --git a/server/controllers/api/claim/update/index.js b/server/controllers/api/claim/update/index.js
index 74ad8c9a..f2c47594 100644
--- a/server/controllers/api/claim/update/index.js
+++ b/server/controllers/api/claim/update/index.js
@@ -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,
diff --git a/server/controllers/assets/utils/serveFile.js b/server/controllers/assets/utils/serveFile.js
index dce8f984..13b647ee 100644
--- a/server/controllers/assets/utils/serveFile.js
+++ b/server/controllers/assets/utils/serveFile.js
@@ -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);
}
};
diff --git a/server/lbrynet/index.js b/server/lbrynet/index.js
index 52633e07..6259dd0f 100644
--- a/server/lbrynet/index.js
+++ b/server/lbrynet/index.js
@@ -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();
diff --git a/server/utils/awaitFileSize.js b/server/utils/awaitFileSize.js
new file mode 100644
index 00000000..c1a9543e
--- /dev/null
+++ b/server/utils/awaitFileSize.js
@@ -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;
diff --git a/server/utils/getClaimData.js b/server/utils/getClaimData.js
index b95d0847..2a3837f5 100644
--- a/server/utils/getClaimData.js
+++ b/server/utils/getClaimData.js
@@ -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,
};
};
diff --git a/server/utils/isValidQueryObj.js b/server/utils/isValidQueryObj.js
new file mode 100644
index 00000000..cbebb337
--- /dev/null
+++ b/server/utils/isValidQueryObj.js
@@ -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;
diff --git a/utils/createModuleAliases.js b/utils/createModuleAliases.js
index eea3edb4..47560faa 100644
--- a/utils/createModuleAliases.js
+++ b/utils/createModuleAliases.js
@@ -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;
};