Compare commits
154 commits
Author | SHA1 | Date | |
---|---|---|---|
|
363c079433 | ||
|
8ca76a6de1 | ||
|
99c7b087d7 | ||
|
67e198db2f | ||
|
50805ad4ea | ||
|
b410eb8c94 | ||
|
efc38529c7 | ||
|
dfa6db6276 | ||
|
5215bfbc4e | ||
|
2b4a379638 | ||
|
9df4d29dda | ||
|
68b6f484e4 | ||
|
7584d0c7e3 | ||
|
7940c61b17 | ||
|
3d36f136f1 | ||
|
5ed72b0e14 | ||
|
922a53cc30 | ||
|
d11ba6225e | ||
|
a8678f5d1f | ||
|
423c0c9311 | ||
|
3d23635bf5 | ||
|
707e144eff | ||
|
ad87e2b8a7 | ||
|
01ae90fc15 | ||
|
1e6cb2a7c6 | ||
|
2e7d4c5112 | ||
|
15e4a97e6a | ||
|
5dc89f0a91 | ||
|
0974e6d6b0 | ||
|
64d7afd278 | ||
|
648639e6c6 | ||
|
8ded28beb3 | ||
|
b1a9d8ee74 | ||
|
9e76553f0a | ||
|
f4a50d0c85 | ||
|
23953a32e8 | ||
|
aa4a43a1a5 | ||
|
eba7fd596f | ||
|
9130b6f609 | ||
|
94f5f6dc69 | ||
|
269a2c57a7 | ||
|
1fd0ec1fc2 | ||
|
53e0d2a0db | ||
|
aebaa4f954 | ||
|
5b2108796c | ||
|
200903827a | ||
|
993b1d31e9 | ||
|
8891f298ae | ||
|
9bd779775a | ||
|
322b8a147d | ||
|
424827ea15 | ||
|
15e7456a88 | ||
|
d4e38db1ae | ||
|
d3f4c0aefb | ||
|
ee004405a6 | ||
|
6313c7eeff | ||
|
ee1b5c68bc | ||
|
962d07a6c9 | ||
|
a27f6e2b21 | ||
|
848077b057 | ||
|
b9b4333b55 | ||
|
ac3e9d1e67 | ||
|
bd0c3fd4c3 | ||
|
85cc743f90 | ||
|
0e357b7b56 | ||
|
2311e5685f | ||
|
a66511caaf | ||
|
39095c16a9 | ||
|
3d4ad3d827 | ||
|
6992b87033 | ||
|
75818e47fe | ||
|
4cfb85fed3 | ||
|
8a6cd2db13 | ||
|
dee61b5b6f | ||
|
82ab3b47b1 | ||
|
73667d4d9a | ||
|
0b4eab9bb6 | ||
|
68d2f303c1 | ||
|
b98fffc386 | ||
|
adbafa4194 | ||
|
1b069ba2a1 | ||
|
5f3f5c678a | ||
|
5ab338cfa5 | ||
|
ec9f78de16 | ||
|
b2624026bb | ||
|
2ec4f366b0 | ||
|
b2e35c7e13 | ||
|
bf26e7d8a9 | ||
|
8279b92a46 | ||
|
e21761e278 | ||
|
1a9ceef1e0 | ||
|
87ca19d700 | ||
|
13cee683c3 | ||
|
c97685cfb5 | ||
|
792bb51134 | ||
|
e210773016 | ||
|
a4cc7460d5 | ||
|
3507bd6bf2 | ||
|
cab6c6dc80 | ||
|
992eefd40c | ||
|
8799e0e320 | ||
|
302442385e | ||
|
4632ee6472 | ||
|
cf221b5aba | ||
|
2b20900ae5 | ||
|
626b3f8b5c | ||
|
373ee83c13 | ||
|
220d043ff6 | ||
|
423c2827bc | ||
|
3411cedb55 | ||
|
eb5473bbb6 | ||
|
790943445f | ||
|
6b97b415ff | ||
|
e6274fe9d8 | ||
|
a9627fbd96 | ||
|
da4a1d6c03 | ||
|
63a1be5287 | ||
|
aa70c2854d | ||
|
c5739b1cb6 | ||
|
665b60d03b | ||
|
161b57fef5 | ||
|
629d133fd2 | ||
|
357388d1e4 | ||
|
5e66b6827a | ||
|
42fc707dba | ||
|
f636023f80 | ||
|
a5700be902 | ||
|
b107346c28 | ||
|
117ffa68a5 | ||
|
3cd7b6080d | ||
|
7b7a0339b8 | ||
|
4c37a6311f | ||
|
f8662dddb1 | ||
|
0d04659498 | ||
|
dfdb933527 | ||
|
7d5e41153e | ||
|
a2c87af728 | ||
|
739127e44f | ||
|
c79573f4d2 | ||
|
8e9e195b8e | ||
|
969988f5e8 | ||
|
961700390a | ||
|
060e34090e | ||
|
aa381d5940 | ||
|
ed9d037155 | ||
|
a6cecf84e2 | ||
|
7a83d4c75f | ||
|
cf97b0d3df | ||
|
ac28b0c43f | ||
|
287464e311 | ||
|
7c157d0b18 | ||
|
b46f641937 | ||
|
48667623db | ||
|
f559b5aae1 |
92 changed files with 1786 additions and 934 deletions
|
@ -1,4 +1,3 @@
|
||||||
sudo: true
|
|
||||||
dist: xenial
|
dist: xenial
|
||||||
#addons:
|
#addons:
|
||||||
# apt:
|
# apt:
|
||||||
|
@ -9,7 +8,7 @@ dist: xenial
|
||||||
# - mysql-client
|
# - mysql-client
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "lts/*"
|
- "lts/dubnium"
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- "node_modules"
|
- "node_modules"
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2017-2019 LBRY Inc.
|
Copyright (c) 2017-2020 LBRY Inc.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
|
||||||
"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
|
19
README.md
19
README.md
|
@ -3,6 +3,8 @@
|
||||||
spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and
|
spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and
|
||||||
blockchain ([LBRY](https://lbry.tech/)). Via just a small set of config files, you can spin your an entire spee.ch site back up including assets.
|
blockchain ([LBRY](https://lbry.tech/)). Via just a small set of config files, you can spin your an entire spee.ch site back up including assets.
|
||||||
|
|
||||||
|
**Please note: the spee.ch code base and setup instructions are no longer actively maintained now that we have lbry.tv. Proceed at your own caution. Setup will require dev ops skills.**
|
||||||
|
|
||||||
![App GIF](https://spee.ch/e/speechgif.gif)
|
![App GIF](https://spee.ch/e/speechgif.gif)
|
||||||
|
|
||||||
For a completely open, unrestricted example of a spee.ch site, check out https://www.spee.ch.
|
For a completely open, unrestricted example of a spee.ch site, check out https://www.spee.ch.
|
||||||
|
@ -47,6 +49,7 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim
|
||||||
- `./lbrynet account_balance` gets your balance (initially 0.0)
|
- `./lbrynet account_balance` gets your balance (initially 0.0)
|
||||||
- `./lbrynet address_list` gets addresses you can use to recieve LBC
|
- `./lbrynet address_list` gets addresses you can use to recieve LBC
|
||||||
- [FFmpeg](https://www.ffmpeg.org/download.html)
|
- [FFmpeg](https://www.ffmpeg.org/download.html)
|
||||||
|
- [ImageMagick](https://packages.ubuntu.com/xenial/graphics/imagemagick)
|
||||||
- Spee.ch (below)
|
- Spee.ch (below)
|
||||||
- pm2 (optional) process manager such as pm2 to run speech server.js
|
- 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
|
- http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000
|
||||||
|
@ -104,7 +107,7 @@ $ npm run start
|
||||||
|
|
||||||
#### Customize your app
|
#### Customize your app
|
||||||
|
|
||||||
Check out the [customization guide](https://github.com/lbryio/spee.ch/blob/readme-update/customize.md) to change your app's appearance and components
|
Check out the [customization guide](https://github.com/lbryio/spee.ch/blob/master/customize.md) to change your app's appearance and components
|
||||||
|
|
||||||
#### (optional) add custom components and update the styles
|
#### (optional) add custom components and update the styles
|
||||||
|
|
||||||
|
@ -118,7 +121,7 @@ Instructions are coming at [lbry-docker] to install your own chainquery instance
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
There are a number of settings available for customizing the behavior of your installation.
|
There are a number of settings available for customizing the behavior of your installation.
|
||||||
_INSERT LINK TO SETTINGS.MD_
|
[Here](https://github.com/lbryio/spee.ch/blob/master/docs/settings.md) is some documentation on them.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
@ -260,9 +263,11 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
|
||||||
- retrieve the controlling `LBRY` claim:
|
- retrieve the controlling `LBRY` claim:
|
||||||
- https://spee.ch/`claim`
|
- https://spee.ch/`claim`
|
||||||
- https://spee.ch/`claim`.`ext` (serve)
|
- https://spee.ch/`claim`.`ext` (serve)
|
||||||
|
- https://spee.ch/`claim`.`ext`&`querystring` (serve transformed)
|
||||||
- retrieve a specific `LBRY` claim:
|
- retrieve a specific `LBRY` claim:
|
||||||
- https://spee.ch/`claim_id`/`claim`
|
- https://spee.ch/`claim_id`/`claim`
|
||||||
- https://spee.ch/`claim_id`/`claim`.`ext` (serve)
|
- 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
|
- retrieve all contents for the controlling `LBRY` channel
|
||||||
- https://spee.ch/`@channel`
|
- https://spee.ch/`@channel`
|
||||||
- a specific `LBRY` channel
|
- a specific `LBRY` channel
|
||||||
|
@ -270,9 +275,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
|
- retrieve a specific claim within the controlling `LBRY` channel
|
||||||
- https://spee.ch/`@channel`/`claim`
|
- https://spee.ch/`@channel`/`claim`
|
||||||
- https://spee.ch/`@channel`/`claim`.`ext` (serve)
|
- https://spee.ch/`@channel`/`claim`.`ext` (serve)
|
||||||
|
- https://spee.ch/`@channel`/`claim`.`ext`&`querystring` (serve)
|
||||||
- retrieve a specific claim within a specific `LBRY` channel
|
- retrieve a specific claim within a specific `LBRY` channel
|
||||||
- https://spee.ch/`@channel`:`channel_id`/`claim`
|
- https://spee.ch/`@channel`:`channel_id`/`claim`
|
||||||
- https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve)
|
- 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
|
### Dependencies
|
||||||
|
|
||||||
|
@ -291,8 +302,8 @@ This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
We take security seriously. Please contact security@lbry.io regarding any security issues. [Our GPG key is here](https://lbry.io/faq/gpg-key) if you need it.
|
We take security seriously. Please contact security@lbry.com regarding any security issues. [Our GPG key is here](https://lbry.com/faq/gpg-key) if you need it.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
The primary contact for this project is [@jessopb](mailto:jessop@lbry.io).
|
The primary contact for this project is [@jessopb](mailto:jessop@lbry.com).
|
||||||
|
|
0
changelog.md
Normal file
0
changelog.md
Normal file
|
@ -188,8 +188,8 @@ inquirer
|
||||||
.post('http://localhost:5279', {
|
.post('http://localhost:5279', {
|
||||||
method: 'channel_new',
|
method: 'channel_new',
|
||||||
params: {
|
params: {
|
||||||
channel_name: thumbnailChannelDefault,
|
name: thumbnailChannelDefault,
|
||||||
amount: channelBid,
|
bid: channelBid,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
@ -197,7 +197,6 @@ inquirer
|
||||||
if (response.data.error) {
|
if (response.data.error) {
|
||||||
throw new Error(response.data.error.message);
|
throw new Error(response.data.error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbnailChannel = thumbnailChannelDefault;
|
thumbnailChannel = thumbnailChannelDefault;
|
||||||
thumbnailChannelId = response.data.result.claim_id;
|
thumbnailChannelId = response.data.result.claim_id;
|
||||||
siteConfig['publishing']['thumbnailChannel'] = thumbnailChannel;
|
siteConfig['publishing']['thumbnailChannel'] = thumbnailChannel;
|
||||||
|
@ -237,7 +236,9 @@ inquirer
|
||||||
'\nIt\'s a good idea to BACK UP YOUR MASTER PASSWORD \nin "/site/private/authConfig.json" so that you don\'t lose \ncontrol of your channel.'
|
'\nIt\'s a good idea to BACK UP YOUR MASTER PASSWORD \nin "/site/private/authConfig.json" so that you don\'t lose \ncontrol of your channel.'
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('\nNext step: run "npm run start" to build and start your server!');
|
console.log(
|
||||||
|
'\nNext step: run "npm run build" (or "npm run dev") to compiles, and "npm run start" to start your server!'
|
||||||
|
);
|
||||||
console.log(
|
console.log(
|
||||||
'If you want to change any settings, you can edit the files in the "/site" folder.'
|
'If you want to change any settings, you can edit the files in the "/site" folder.'
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"host": "public.chainquery.lbry.io",
|
"host": "public.chainquery.lbry.com",
|
||||||
"port": "3306",
|
"port": "3306",
|
||||||
"timeout": 30,
|
"timeout": 30,
|
||||||
"database": "chainquery",
|
"database": "chainquery",
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
"host": "https://www.example.com",
|
"host": "https://www.example.com",
|
||||||
"description": "A decentralized hosting platform built on LBRY",
|
"description": "A decentralized hosting platform built on LBRY",
|
||||||
"twitter": false,
|
"twitter": false,
|
||||||
"blockListEndpoint": "https://api.lbry.io/file/list_blocked"
|
"blockListEndpoint": "https://api.lbry.com/file/list_blocked"
|
||||||
},
|
},
|
||||||
"publishing": {
|
"publishing": {
|
||||||
"primaryClaimAddress": null,
|
"primaryClaimAddress": null,
|
||||||
"uploadDirectory": "/home/lbry/Uploads",
|
"uploadDirectory": "/home/lbry/Uploads",
|
||||||
"lbrynetHome": "/CURRENTLYUNUSED",
|
|
||||||
"thumbnailChannel": null,
|
"thumbnailChannel": null,
|
||||||
"thumbnailChannelId": null,
|
"thumbnailChannelId": null,
|
||||||
"additionalClaimAddresses": [],
|
"additionalClaimAddresses": [],
|
||||||
|
@ -46,12 +45,13 @@
|
||||||
"customByContentType": {
|
"customByContentType": {
|
||||||
"application/octet-stream": 50000000
|
"application/octet-stream": 50000000
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"maxSizeImage": 10000000,
|
|
||||||
"maxSizeGif": 50000000,
|
|
||||||
"maxSizeVideo": 50000000
|
|
||||||
},
|
},
|
||||||
"serving": {
|
"serving": {
|
||||||
|
"dynamicFileSizing": {
|
||||||
|
"enabled": true,
|
||||||
|
"maxDimension": 2000
|
||||||
|
},
|
||||||
"markdownSettings": {
|
"markdownSettings": {
|
||||||
"skipHtmlMain": true,
|
"skipHtmlMain": true,
|
||||||
"escapeHtmlMain": true,
|
"escapeHtmlMain": true,
|
||||||
|
@ -86,24 +86,21 @@
|
||||||
"code",
|
"code",
|
||||||
"html",
|
"html",
|
||||||
"parsedHtml"
|
"parsedHtml"
|
||||||
],
|
]
|
||||||
"disallowedTypesMain": [],
|
|
||||||
"disallowedTypesDescriptions": ["image", "html"],
|
|
||||||
"disallowedTypesExample": ["image", "html"]
|
|
||||||
},
|
},
|
||||||
"customFileExtensions": {
|
"customFileExtensions": {
|
||||||
"application/x-troff-man": ".man",
|
"application/x-troff-man": "man",
|
||||||
"application/x-troff-me": ".me",
|
"application/x-troff-me": "me",
|
||||||
"application/x-mif": ".mif",
|
"application/x-mif": "mif",
|
||||||
"application/x-troff-ms": ".ms",
|
"application/x-troff-ms": "ms",
|
||||||
"application/x-troff": ".roff",
|
"application/x-troff": "roff",
|
||||||
"application/x-python-code": ".pyc",
|
"application/x-python-code": "pyc",
|
||||||
"text/x-python": ".py",
|
"text/x-python": "py",
|
||||||
"application/x-pn-realaudio": ".ram",
|
"application/x-pn-realaudio": "ram",
|
||||||
"application/x-sgml": ".sgm",
|
"application/x-sgml": "sgm",
|
||||||
"model/stl": ".stl",
|
"model/stl": "stl",
|
||||||
"image/pict": ".pct",
|
"image/pict": "pct",
|
||||||
"text/xul": ".xul",
|
"text/xul": "xul",
|
||||||
"text/x-go": "go"
|
"text/x-go": "go"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,29 +1,88 @@
|
||||||
.asset-preview {
|
.asset-preview {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
background: $card-color;
|
background: $card-color;
|
||||||
padding: $thin-padding;
|
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
border: $subtle-border;
|
border: $subtle-border;
|
||||||
height: 280px;
|
height: 256px;
|
||||||
&:hover {
|
&:hover {
|
||||||
border: 1px solid $highlight-border-color;
|
border-color: $highlight-border-color;
|
||||||
color: #000000;
|
color: $primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asset-preview__image {
|
||||||
|
height : 180px;
|
||||||
|
width : 240px;
|
||||||
|
overflow: hidden;
|
||||||
|
object-fit: cover;
|
||||||
|
padding: 0;
|
||||||
|
margin : 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-preview__image-box {
|
||||||
|
width : 240px;
|
||||||
|
height : 180px;
|
||||||
|
padding: 0;
|
||||||
|
margin : 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.asset-preview__label {
|
.asset-preview__label {
|
||||||
|
padding: $thin-padding;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 7.3em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.asset-preview__label-text {
|
.asset-preview__label-text {
|
||||||
height: 4.5em;
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: $text-small;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-preview__label-info {
|
||||||
|
width: 100%;
|
||||||
|
height: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-preview__label-info-datum {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: $text-small;
|
||||||
|
max-width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-preview__label-info-datum svg{
|
||||||
|
height: 1.2em;
|
||||||
|
width: 1.2em;
|
||||||
|
padding: 0;
|
||||||
|
padding-right: $thin-padding;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-preview__label-info-datum .svg-icon{
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0;
|
||||||
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.asset-preview__blocked {
|
.asset-preview__blocked {
|
||||||
|
@ -34,22 +93,3 @@
|
||||||
padding: $thin-padding;
|
padding: $thin-padding;
|
||||||
margin-bottom: $thin-padding;
|
margin-bottom: $thin-padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
.asset-preview__image {
|
|
||||||
width : 240px;
|
|
||||||
height : 180px;
|
|
||||||
overflow: hidden;
|
|
||||||
object-fit: cover;
|
|
||||||
padding: 0;
|
|
||||||
margin : 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3.asset-preview__title {
|
|
||||||
margin: 0;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
max-height: 4em;
|
|
||||||
font-size: $text-large;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
.channel-claims-display {
|
.channel-claims-display {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: $thin-padding;
|
grid-gap: $tertiary-padding;
|
||||||
align-content: space-around;
|
align-content: space-around;
|
||||||
@media (min-width: $break-point-x-large) {
|
@media (min-width: $break-point-x-large) {
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
|
|
@ -8,6 +8,7 @@ input {
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: $background-color;
|
background-color: $background-color;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
color: $text-color
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-slider {
|
.input-slider {
|
||||||
|
|
|
@ -9,7 +9,6 @@ a, a:visited {
|
||||||
|
|
||||||
.link--nav {
|
.link--nav {
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
border-bottom: 2px solid white;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
.nav-bar {
|
.nav-bar {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: $thin-padding $primary-padding;
|
padding: $thin-padding $primary-padding;
|
||||||
background: $base-color;
|
background: $chrome-color;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: $subtle-border;
|
border-bottom: $subtle-border;
|
||||||
|
color: $primary-color;
|
||||||
|
|
||||||
@media (max-width: $break-point-mobile) {
|
@media (max-width: $break-point-mobile) {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
input {
|
||||||
|
background: $chrome-color;
|
||||||
|
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
background: $chrome-color;
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-bar-link {
|
.nav-bar-link {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
select {
|
select {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: $base-color;
|
background: $background-color;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
color: $text-color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//backgrounds
|
//backgrounds
|
||||||
$base-color: white; //default white
|
$base-color: white; //default white
|
||||||
$card-color: white; //default white
|
$card-color: white; //default white
|
||||||
$chrome-color: lightgray; //default white (navbar)
|
$chrome-color: white; //default white (navbar)
|
||||||
$blockquote-background: #EEEEFF;
|
$blockquote-background: #EEEEFF;
|
||||||
$background-color: $base-color;
|
$background-color: $base-color;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ $blockquote-text: $text-color;
|
||||||
$grey: #9095A5;
|
$grey: #9095A5;
|
||||||
$help-color: $grey;
|
$help-color: $grey;
|
||||||
$subtle-border-color: #DDD;
|
$subtle-border-color: #DDD;
|
||||||
$highlight-border-color: #333;
|
$highlight-border-color: #777;
|
||||||
$shadow-color: rgba(169, 173, 186, 0.2);
|
$shadow-color: rgba(169, 173, 186, 0.2);
|
||||||
$subtle-border: 1px dashed $subtle-border-color;
|
$subtle-border: 1px dashed $subtle-border-color;
|
||||||
$grey-border: $subtle-border-color; //factor this out for all customers
|
$grey-border: $subtle-border-color; //factor this out for all customers
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
import * as actions from '../constants/show_action_types';
|
import * as actions from '../constants/show_action_types';
|
||||||
import {
|
import { ASSET_DETAILS, ASSET_LITE, CHANNEL, SPECIAL_ASSET } from '../constants/show_request_types';
|
||||||
ASSET_DETAILS,
|
|
||||||
ASSET_LITE,
|
|
||||||
CHANNEL,
|
|
||||||
SPECIAL_ASSET,
|
|
||||||
} from '../constants/show_request_types';
|
|
||||||
|
|
||||||
// basic request parsing
|
// basic request parsing
|
||||||
export function onHandleShowPageUri (params, url) {
|
export function onHandleShowPageUri(params, url) {
|
||||||
return {
|
return {
|
||||||
type: actions.HANDLE_SHOW_URI,
|
type: actions.HANDLE_SHOW_URI,
|
||||||
data: {
|
data: {
|
||||||
|
@ -17,7 +12,7 @@ export function onHandleShowPageUri (params, url) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onHandleShowHomepage (params, url) {
|
export function onHandleShowHomepage(params, url) {
|
||||||
return {
|
return {
|
||||||
type: actions.HANDLE_SHOW_HOMEPAGE,
|
type: actions.HANDLE_SHOW_HOMEPAGE,
|
||||||
data: {
|
data: {
|
||||||
|
@ -27,14 +22,14 @@ export function onHandleShowHomepage (params, url) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onRequestError (error) {
|
export function onRequestError(error) {
|
||||||
return {
|
return {
|
||||||
type: actions.REQUEST_ERROR,
|
type: actions.REQUEST_ERROR,
|
||||||
data: error,
|
data: error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onNewChannelRequest (channelName, channelId) {
|
export function onNewChannelRequest(channelName, channelId) {
|
||||||
const requestType = CHANNEL;
|
const requestType = CHANNEL;
|
||||||
const requestId = `cr#${channelName}#${channelId}`;
|
const requestId = `cr#${channelName}#${channelId}`;
|
||||||
return {
|
return {
|
||||||
|
@ -43,7 +38,7 @@ export function onNewChannelRequest (channelName, channelId) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onNewSpecialAssetRequest (name) {
|
export function onNewSpecialAssetRequest(name) {
|
||||||
const requestType = SPECIAL_ASSET;
|
const requestType = SPECIAL_ASSET;
|
||||||
const requestId = `sar#${name}`;
|
const requestId = `sar#${name}`;
|
||||||
return {
|
return {
|
||||||
|
@ -52,7 +47,7 @@ export function onNewSpecialAssetRequest (name) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onNewAssetRequest (name, id, channelName, channelId, extension) {
|
export function onNewAssetRequest(name, id, channelName, channelId, extension) {
|
||||||
const requestType = extension ? ASSET_LITE : ASSET_DETAILS;
|
const requestType = extension ? ASSET_LITE : ASSET_DETAILS;
|
||||||
const requestId = `ar#${name}#${id}#${channelName}#${channelId}`;
|
const requestId = `ar#${name}#${id}#${channelName}#${channelId}`;
|
||||||
return {
|
return {
|
||||||
|
@ -65,14 +60,14 @@ export function onNewAssetRequest (name, id, channelName, channelId, extension)
|
||||||
id,
|
id,
|
||||||
channel: {
|
channel: {
|
||||||
name: channelName,
|
name: channelName,
|
||||||
id : channelId,
|
id: channelId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onRequestUpdate (requestType, requestId) {
|
export function onRequestUpdate(requestType, requestId) {
|
||||||
return {
|
return {
|
||||||
type: actions.REQUEST_UPDATE,
|
type: actions.REQUEST_UPDATE,
|
||||||
data: {
|
data: {
|
||||||
|
@ -82,7 +77,7 @@ export function onRequestUpdate (requestType, requestId) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addRequestToRequestList (id, error, key) {
|
export function addRequestToRequestList(id, error, key) {
|
||||||
return {
|
return {
|
||||||
type: actions.REQUEST_LIST_ADD,
|
type: actions.REQUEST_LIST_ADD,
|
||||||
data: { id, error, key },
|
data: { id, error, key },
|
||||||
|
@ -91,21 +86,21 @@ export function addRequestToRequestList (id, error, key) {
|
||||||
|
|
||||||
// asset actions
|
// asset actions
|
||||||
|
|
||||||
export function addAssetToAssetList (id, error, name, claimId, shortId, claimData, claimViews) {
|
export function addAssetToAssetList(id, error, name, claimId, shortId, claimData, claimViews) {
|
||||||
return {
|
return {
|
||||||
type: actions.ASSET_ADD,
|
type: actions.ASSET_ADD,
|
||||||
data: { id, error, name, claimId, shortId, claimData, claimViews },
|
data: { id, error, name, claimId, shortId, claimData, claimViews },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateAssetViewsInList (id, claimId, claimViews) {
|
export function updateAssetViewsInList(id, claimId, claimViews) {
|
||||||
return {
|
return {
|
||||||
type: actions.ASSET_VIEWS_UPDATE,
|
type: actions.ASSET_VIEWS_UPDATE,
|
||||||
data: { id, claimId, claimViews },
|
data: { id, claimId, claimViews },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeAsset (data) {
|
export function removeAsset(data) {
|
||||||
return {
|
return {
|
||||||
type: actions.ASSET_REMOVE,
|
type: actions.ASSET_REMOVE,
|
||||||
data,
|
data,
|
||||||
|
@ -114,7 +109,7 @@ export function removeAsset (data) {
|
||||||
|
|
||||||
// channel actions
|
// channel actions
|
||||||
|
|
||||||
export function addNewChannelToChannelList (id, name, shortId, longId, claimsData) {
|
export function addNewChannelToChannelList(id, name, shortId, longId, claimsData) {
|
||||||
return {
|
return {
|
||||||
type: actions.CHANNEL_ADD,
|
type: actions.CHANNEL_ADD,
|
||||||
data: {
|
data: {
|
||||||
|
@ -127,39 +122,47 @@ export function addNewChannelToChannelList (id, name, shortId, longId, claimsDat
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onUpdateChannelClaims (channelKey, name, longId, page) {
|
export function onUpdateChannelClaims(channelKey, name, longId, page) {
|
||||||
return {
|
return {
|
||||||
type: actions.CHANNEL_CLAIMS_UPDATE_ASYNC,
|
type: actions.CHANNEL_CLAIMS_UPDATE_ASYNC,
|
||||||
data: {channelKey, name, longId, page},
|
data: { channelKey, name, longId, page },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateChannelClaims (channelListId, claimsData) {
|
export function updateChannelClaims(channelListId, claimsData) {
|
||||||
return {
|
return {
|
||||||
type: actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED,
|
type: actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED,
|
||||||
data: {channelListId, claimsData},
|
data: { channelListId, claimsData },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// display a file
|
// display a file
|
||||||
|
|
||||||
export function fileRequested (name, claimId) {
|
export function fileRequested(name, claimId) {
|
||||||
return {
|
return {
|
||||||
type: actions.FILE_REQUESTED,
|
type: actions.FILE_REQUESTED,
|
||||||
data: { name, claimId },
|
data: { name, claimId },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateFileAvailability (status) {
|
export function updateFileAvailability(status) {
|
||||||
return {
|
return {
|
||||||
type: actions.FILE_AVAILABILITY_UPDATE,
|
type: actions.FILE_AVAILABILITY_UPDATE,
|
||||||
data: status,
|
data: status,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateDisplayAssetError (error) {
|
export function updateDisplayAssetError(error) {
|
||||||
return {
|
return {
|
||||||
type: actions.DISPLAY_ASSET_ERROR,
|
type: actions.DISPLAY_ASSET_ERROR,
|
||||||
data: error,
|
data: error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// viewer settings
|
||||||
|
export function toggleDetailsExpanded(isExpanded) {
|
||||||
|
return {
|
||||||
|
type: actions.TOGGLE_DETAILS_EXPANDED,
|
||||||
|
data: isExpanded,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Request from '../utils/request';
|
import Request from '../utils/request';
|
||||||
|
|
||||||
export function getLongClaimId (host, name, modifier) {
|
export function getLongClaimId(host, name, modifier) {
|
||||||
let body = {};
|
let body = {};
|
||||||
// create request params
|
// create request params
|
||||||
if (modifier) {
|
if (modifier) {
|
||||||
|
@ -13,40 +13,40 @@ export function getLongClaimId (host, name, modifier) {
|
||||||
}
|
}
|
||||||
body['claimName'] = name;
|
body['claimName'] = name;
|
||||||
const params = {
|
const params = {
|
||||||
method : 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body : JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
};
|
};
|
||||||
// create url
|
// create url
|
||||||
const url = `${host}/api/claim/long-id`;
|
const url = `${host}/api/claim/long-id`;
|
||||||
// return the request promise
|
// return the request promise
|
||||||
return Request(url, params);
|
return Request(url, params);
|
||||||
};
|
}
|
||||||
|
|
||||||
export function getShortId (host, name, claimId) {
|
export function getShortId(host, name, claimId) {
|
||||||
const url = `${host}/api/claim/short-id/${claimId}/${name}`;
|
const url = `${host}/api/claim/short-id/${claimId}/${name}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
};
|
}
|
||||||
|
|
||||||
export function getClaimData (host, name, claimId) {
|
export function getClaimData(host, name, claimId) {
|
||||||
const url = `${host}/api/claim/data/${name}/${claimId}`;
|
const url = `${host}/api/claim/data/${name}/${claimId}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
};
|
}
|
||||||
|
|
||||||
export function checkClaimAvailability (claim) {
|
export function checkClaimAvailability(claim) {
|
||||||
const url = `/api/claim/availability/${claim}`;
|
const url = `/api/claim/availability/${claim}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getClaimViews (claimId) {
|
export function getClaimViews(claimId) {
|
||||||
const url = `/api/claim/views/${claimId}`;
|
const url = `/api/claim/views/${claimId}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doAbandonClaim (claimId) {
|
export function doAbandonClaim(outpoint) {
|
||||||
const params = {
|
const params = {
|
||||||
method : 'POST',
|
method: 'POST',
|
||||||
body : JSON.stringify({claimId}),
|
body: JSON.stringify({ outpoint }),
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -16,7 +16,7 @@ import EditPage from '@pages/EditPage';
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path='/' component={HomePage} />
|
<Route exact path='/' component={AboutPage} />
|
||||||
<Route exact path='/about' component={AboutPage} />
|
<Route exact path='/about' component={AboutPage} />
|
||||||
<Route exact path='/tos' component={TosPage} />
|
<Route exact path='/tos' component={TosPage} />
|
||||||
<Route exact path='/faq' component={FaqPage} />
|
<Route exact path='/faq' component={FaqPage} />
|
||||||
|
|
|
@ -22,15 +22,30 @@ export const makePublishRequestChannel = (fd, isUpdate) => {
|
||||||
xhr.upload.addEventListener('load', onLoad);
|
xhr.upload.addEventListener('load', onLoad);
|
||||||
// set state change handler
|
// set state change handler
|
||||||
xhr.onreadystatechange = () => {
|
xhr.onreadystatechange = () => {
|
||||||
if (xhr.readyState === 4) {
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
const response = JSON.parse(xhr.response);
|
switch (xhr.status) {
|
||||||
if ((xhr.status === 200) && response.success) {
|
case 413:
|
||||||
|
emitter({error: new Error("Unfortunately it appears this web server " +
|
||||||
|
"has been misconfigured, please inform the service administrators " +
|
||||||
|
"that they must set their nginx/apache request size maximums higher " +
|
||||||
|
"than their file size limits.")});
|
||||||
|
emitter(END);
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
var response = JSON.parse(xhr.response);
|
||||||
|
if (response.success) {
|
||||||
emitter({success: response});
|
emitter({success: response});
|
||||||
emitter(END);
|
emitter(END);
|
||||||
} else {
|
} else {
|
||||||
emitter({error: new Error(response.message)});
|
emitter({error: new Error(response.message)});
|
||||||
emitter(END);
|
emitter(END);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
emitter({error: new Error("Received an unexpected response from " +
|
||||||
|
"server: " + xhr.status)});
|
||||||
|
emitter(END);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// open and send
|
// open and send
|
||||||
|
|
|
@ -1,32 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Row from '@components/Row';
|
import Row from '@components/Row';
|
||||||
import {Link} from 'react-router-dom';
|
|
||||||
|
|
||||||
const AboutSpeechDetails = () => {
|
const AboutSpeechDetails = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Row>
|
<Row>
|
||||||
<p className={'text--large'}>
|
<p className={'text--large'}>
|
||||||
<Link className={'link--primary'} to='/tos'>Terms of Service</Link>
|
Spee.ch's journey may be on hold, but LBRY is still on mission. We'd like to thank all of our testers and early adopters for helping us explore this use case.
|
||||||
<br />
|
We're really excited about <a className='link--primary' href='https://lbry.tv' target='_blank'>lbry.tv</a> and can't wait to see you over there for a fully featured experience.
|
||||||
<Link className={'link--primary'} to='/faq'>Frequently Asked Questions</Link>
|
|
||||||
</p>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<p className={'text--large'}>
|
|
||||||
Spee.ch is a media-hosting site that reads from and publishes content to the <a className='link--primary' href='https://lbry.io'>LBRY</a> blockchain.
|
|
||||||
</p>
|
|
||||||
<p className={'text--large'}>
|
|
||||||
Spee.ch is a hosting service, but with the added benefit that it stores your content on a decentralized network of computers -- the <a className='link--primary' href='https://lbry.io/get'>LBRY</a> network. This means that your images are stored in multiple locations without a single point of failure.
|
|
||||||
</p>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<h3>Contribute</h3>
|
|
||||||
<p className={'text--large'}>
|
|
||||||
If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a className='link--primary' href='https://github.com/lbryio/spee.ch'>github repo</a> and go to town!
|
|
||||||
</p>
|
|
||||||
<p className={'text--large'}>
|
|
||||||
If you want to improve spee.ch, join our <a className='link--primary' href='https://chat.lbry.io'>discord channel</a> or solve one of our <a className='link--primary' href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.
|
|
||||||
</p>
|
</p>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,14 +5,13 @@ const AboutSpeechOverview = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Row>
|
<Row>
|
||||||
<p className={'text--extra-large'}>Spee.ch is an open-source project. Please contribute to the existing site, or fork it and make your own.</p>
|
<p className={'text--extra-large'}>Lbry is no longer supporting Spee.ch. However, we're excited to show you <a className='link--primary' href='https://lbry.tv' target='_blank'>lbry.tv</a>!</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<div className={'text--large'}>
|
<div className={'text--large'}>
|
||||||
<a className='link--primary' target='_blank' href='https://twitter.com/spee_ch'>TWITTER</a><br/>
|
<a className='link--primary' target='_blank' href='https://twitter.com/lbry'>TWITTER</a><br/>
|
||||||
<a className='link--primary' target='_blank' href='https://github.com/lbryio/spee.ch'>GITHUB</a><br/>
|
<a className='link--primary' target='_blank' href='https://github.com/lbryio/'>GITHUB</a><br/>
|
||||||
<a className='link--primary' target='_blank' href='https://discord.gg/YjYbwhS'>DISCORD CHANNEL</a><br/>
|
<a className='link--primary' target='_blank' href='https://discord.gg/YjYbwhS'>DISCORD CHANNEL</a><br/>
|
||||||
<a className='link--primary' target='_blank' href='https://github.com/lbryio/spee.ch/blob/master/README.md'>DOCUMENTATION</a><br/>
|
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,9 +3,13 @@ import Row from '@components/Row';
|
||||||
|
|
||||||
const AssetInfoFooter = ({ assetUrl, name }) => {
|
const AssetInfoFooter = ({ assetUrl, name }) => {
|
||||||
return (
|
return (
|
||||||
<div className='asset-footer'>
|
<div className="asset-footer">
|
||||||
<p>
|
<p>
|
||||||
Hosted via the <a className={'link--primary'} href={'https://lbry.io/get'} target={'_blank'}>LBRY</a> blockchain
|
Hosted via the{' '}
|
||||||
|
<a className={'link--primary'} href={'https://lbry.com/get'} target={'_blank'}>
|
||||||
|
LBRY
|
||||||
|
</a>{' '}
|
||||||
|
blockchain
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,11 +2,24 @@ import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||||
import * as Icon from 'react-feather';
|
import * as Icon from 'react-feather';
|
||||||
|
import Img from 'react-image';
|
||||||
|
|
||||||
const AssetPreview = ({ defaultThumbnail, claimData }) => {
|
const AssetPreview = ({ defaultThumbnail, claimData }) => {
|
||||||
const {name, fileExt, contentType, thumbnail, title, blocked} = claimData;
|
const {name, fileExt, contentType, thumbnail, title, blocked, transactionTime = 0} = claimData;
|
||||||
const showUrl = createCanonicalLink({asset: {...claimData}});
|
const showUrl = createCanonicalLink({asset: {...claimData}});
|
||||||
const embedUrl = `${showUrl}.${fileExt}`;
|
const embedUrl = `${showUrl}.${fileExt}`;
|
||||||
|
const ago = Date.now() / 1000 - transactionTime;
|
||||||
|
const dayInSeconds = 60 * 60 * 24;
|
||||||
|
const monthInSeconds = dayInSeconds * 30;
|
||||||
|
let when;
|
||||||
|
|
||||||
|
if (ago < dayInSeconds || transactionTime < 1) {
|
||||||
|
when = 'Just today';
|
||||||
|
} else if (ago < monthInSeconds) {
|
||||||
|
when = `${Math.floor(ago / dayInSeconds)} d ago`;
|
||||||
|
} else {
|
||||||
|
when = `${Math.floor(ago / monthInSeconds)} mo ago`;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
we'll be assigning media icon based on supported type / mime types
|
we'll be assigning media icon based on supported type / mime types
|
||||||
*/
|
*/
|
||||||
|
@ -37,22 +50,37 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Link to={showUrl} className='asset-preview'>
|
<Link to={showUrl} className='asset-preview'>
|
||||||
<img
|
<div className='asset-preview__image-box'>
|
||||||
className={'asset-preview__image'}
|
<Img
|
||||||
src={thumb || defaultThumbnail}
|
src={[
|
||||||
|
thumb,
|
||||||
|
defaultThumbnail,
|
||||||
|
'/assets/img/default_thumb.jpg',
|
||||||
|
]}
|
||||||
alt={name}
|
alt={name}
|
||||||
|
className={'asset-preview__image'}
|
||||||
/>
|
/>
|
||||||
<div className={'asset-preview__label'}>
|
|
||||||
<div className={'asset-preview__label-text'}>
|
|
||||||
<p className='asset-preview__title text--medium'>{title}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={'asset-preview__label-info'}>
|
|
||||||
<div className={'text--medium'}>
|
<div className={'asset-preview__label'}>
|
||||||
|
|
||||||
|
<div className={'asset-preview__label-text'}>
|
||||||
|
<p>{title}</p>
|
||||||
|
</div>
|
||||||
|
<div className={'asset-preview__label-info '}>
|
||||||
|
<div className={'asset-preview__label-info-datum'}>
|
||||||
|
<div className={'svg-icon'}>
|
||||||
{ media === 'image' && <Icon.Image />}
|
{ media === 'image' && <Icon.Image />}
|
||||||
{ media === 'text' && <Icon.FileText />}
|
{ media === 'text' && <Icon.FileText />}
|
||||||
{ media === 'video' && contentType === 'video/mp4' && <Icon.Video />}
|
{ media === 'video' && contentType === 'video/mp4' && <Icon.Video />}
|
||||||
{ media !== 'image' && media !== 'text' && contentType !== 'video/mp4' && <Icon.File />}
|
{ media !== 'image' && media !== 'text' && contentType !== 'video/mp4' && <Icon.File />}
|
||||||
</div>
|
</div>
|
||||||
|
<div>{fileExt}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'asset-preview__label-info-datum'}>
|
||||||
|
<div>{when}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
const PublishFinePrint = () => {
|
const PublishFinePrint = () => {
|
||||||
return (
|
return (
|
||||||
<p className={'text--extra-small text--secondary'}>
|
<p className={'text--extra-small text--secondary'}>
|
||||||
By clicking 'Publish', you affirm that you have the rights to publish this content to the LBRY network, and that you understand the properties of publishing it to a decentralized, user-controlled network. <a className='link--primary' target='_blank' href='https://lbry.io/learn'>Read more.</a>
|
By clicking 'Publish', you affirm that you have the rights to publish this content to the LBRY network, and that you understand the properties of publishing it to a decentralized, user-controlled network. <a className='link--primary' target='_blank' href='https://lbry.com/learn'>Read more.</a>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RowLabeled from '@components/RowLabeled';
|
import RowLabeled from '@components/RowLabeled';
|
||||||
import Label from '@components/Label';
|
import Label from '@components/Label';
|
||||||
|
import { LICENSES } from '@clientConstants/publish_license_urls';
|
||||||
|
|
||||||
const PublishLicenseInput = ({ handleSelect }) => {
|
const PublishLicenseInput = ({ handleSelect, license }) => {
|
||||||
return (
|
return (
|
||||||
<RowLabeled
|
<RowLabeled
|
||||||
label={
|
label={
|
||||||
<Label value={'License:'} />
|
<Label value={'License'} />
|
||||||
}
|
}
|
||||||
content={
|
content={
|
||||||
<select
|
<select
|
||||||
type='text'
|
type='text'
|
||||||
name='license'
|
name='license'
|
||||||
id='publish-license'
|
id='publish-license'
|
||||||
|
value={license}
|
||||||
onChange={handleSelect}
|
onChange={handleSelect}
|
||||||
>
|
>
|
||||||
<option value=''>Unspecified</option>
|
<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>
|
</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';
|
|
@ -24,3 +24,4 @@ export const CHANNEL_CLAIMS_UPDATE_SUCCEEDED = 'CHANNEL_CLAIMS_UPDATE_SUCCEEDED'
|
||||||
export const FILE_REQUESTED = 'FILE_REQUESTED';
|
export const FILE_REQUESTED = 'FILE_REQUESTED';
|
||||||
export const FILE_AVAILABILITY_UPDATE = 'FILE_AVAILABILITY_UPDATE';
|
export const FILE_AVAILABILITY_UPDATE = 'FILE_AVAILABILITY_UPDATE';
|
||||||
export const DISPLAY_ASSET_ERROR = 'DISPLAY_ASSET_ERROR';
|
export const DISPLAY_ASSET_ERROR = 'DISPLAY_ASSET_ERROR';
|
||||||
|
export const TOGGLE_DETAILS_EXPANDED = 'TOGGLE_DETAILS_EXPANDED';
|
||||||
|
|
|
@ -17,7 +17,7 @@ class BlockedRight extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<div className={'asset-blocked__text'} >
|
<div className={'asset-blocked__text'} >
|
||||||
<p>In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications.</p>
|
<p>In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications.</p>
|
||||||
<p><a href={'https://lbry.io/faq/dmca'} >Click here</a> for more information.</p>
|
<p><a href={'https://lbry.com/faq/dmca'} >Click here</a> for more information.</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import ProgressBar from '@components/ProgressBar';
|
||||||
import { LOCAL_CHECK, UNAVAILABLE, ERROR, AVAILABLE } from '../../constants/asset_display_states';
|
import { LOCAL_CHECK, UNAVAILABLE, ERROR, AVAILABLE } from '../../constants/asset_display_states';
|
||||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||||
import FileViewer from '@components/FileViewer';
|
import FileViewer from '@components/FileViewer';
|
||||||
|
import isBot from 'isbot';
|
||||||
|
import Img from 'react-image';
|
||||||
|
|
||||||
class AvailableContent extends React.Component {
|
class AvailableContent extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
|
@ -15,20 +17,23 @@ class AvailableContent extends React.Component {
|
||||||
case 'image/gif':
|
case 'image/gif':
|
||||||
case 'image/svg+xml':
|
case 'image/svg+xml':
|
||||||
return (
|
return (
|
||||||
<img
|
<Img
|
||||||
className='asset-image'
|
src={[
|
||||||
src={sourceUrl}
|
sourceUrl,
|
||||||
|
'/assets/img/default_thumb.jpg',
|
||||||
|
]}
|
||||||
alt={name}
|
alt={name}
|
||||||
|
className={'asset-image'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'video/mp4':
|
case 'video/mp4':
|
||||||
return (
|
return (
|
||||||
<video
|
<video
|
||||||
className='asset-video'
|
className='asset-video'
|
||||||
controls poster={thumbnail}
|
controls poster={!!thumbnail && thumbnail || '/assets/img/default_thumb.jpg'}
|
||||||
>
|
>
|
||||||
<source
|
<source
|
||||||
src={sourceUrl}
|
src={!!sourceUrl && sourceUrl}
|
||||||
/>
|
/>
|
||||||
<p>Your browser does not support the <code>video</code> element.</p>
|
<p>Your browser does not support the <code>video</code> element.</p>
|
||||||
</video>
|
</video>
|
||||||
|
@ -36,14 +41,25 @@ class AvailableContent extends React.Component {
|
||||||
case 'text/markdown':
|
case 'text/markdown':
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'asset-document'}><FileViewer sourceUrl={sourceUrl}/></div>
|
(isBot(window.navigator.userAgent))
|
||||||
|
? (
|
||||||
|
<img
|
||||||
|
className='asset-image'
|
||||||
|
src={'/assets/img/default_thumb.jpg'}
|
||||||
|
alt={'markdown available on page load'}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: <div className={'asset-document'}><FileViewer sourceUrl={!!sourceUrl && sourceUrl}/></div>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<img
|
<Img
|
||||||
className='asset-image'
|
src={[
|
||||||
src={thumbnail}
|
thumbnail,
|
||||||
|
'/assets/img/default_thumb.jpg',
|
||||||
|
]}
|
||||||
alt={name}
|
alt={name}
|
||||||
|
className={'asset-image'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +92,7 @@ class AssetDisplay extends React.Component {
|
||||||
<div>
|
<div>
|
||||||
<p>Sit tight, we're searching the LBRY blockchain for your asset!</p>
|
<p>Sit tight, we're searching the LBRY blockchain for your asset!</p>
|
||||||
<ProgressBar size={12} />
|
<ProgressBar size={12} />
|
||||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.io/faq/what-is-lbry'>Learn more.</a></p>
|
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.com/faq/what-is-lbry'>Learn more.</a></p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{(status === ERROR) && (
|
{(status === ERROR) && (
|
||||||
|
@ -87,7 +103,7 @@ class AssetDisplay extends React.Component {
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Row>
|
<Row>
|
||||||
<p>Unfortunately, we couldn't download your asset from LBRY. You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>LBRY discord</a>.</p>
|
<p>Unfortunately, we couldn't download your asset from LBRY. You can help us out by sharing the following error message in the <a className='link--primary' href='https://chat.lbry.com' target='_blank'>LBRY discord</a>.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<p id='error-message'><i>{error}</i></p>
|
<p id='error-message'><i>{error}</i></p>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import AssetShareButtons from '@components/AssetShareButtons';
|
||||||
import ClickToCopy from '@components/ClickToCopy';
|
import ClickToCopy from '@components/ClickToCopy';
|
||||||
import siteConfig from '@config/siteConfig.json';
|
import siteConfig from '@config/siteConfig.json';
|
||||||
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
import createCanonicalLink from '@globalutils/createCanonicalLink';
|
||||||
import AssetInfoFooter from '../../components/AssetInfoFooter/index';
|
import AssetInfoFooter from '@components/AssetInfoFooter/index';
|
||||||
import { createPermanentURI } from '@clientutils/createPermanentURI';
|
import { createPermanentURI } from '@clientutils/createPermanentURI';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
|
@ -18,7 +18,20 @@ class AssetInfo extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
const { editable, asset } = this.props;
|
const { editable, asset } = this.props;
|
||||||
const { claimViews, claimData } = asset;
|
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 canonicalUrl = createCanonicalLink({ asset: { ...claimData, shortId: asset.shortId }});
|
||||||
const assetCanonicalUrl = `${host}${canonicalUrl}`;
|
const assetCanonicalUrl = `${host}${canonicalUrl}`;
|
||||||
|
@ -55,7 +68,7 @@ class AssetInfo extends React.Component {
|
||||||
{editable && (
|
{editable && (
|
||||||
<RowLabeled
|
<RowLabeled
|
||||||
label={<Label value={'Edit'} />}
|
label={<Label value={'Edit'} />}
|
||||||
content={<Link to={`/edit${canonicalUrl}`}>{name}</Link>}
|
content={<Link className='link--primary' to={`/edit${canonicalUrl}`}>{name}</Link>}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{channelName && (
|
{channelName && (
|
||||||
|
@ -71,6 +84,7 @@ class AssetInfo extends React.Component {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<SpaceBetween>
|
||||||
{claimViews ? (
|
{claimViews ? (
|
||||||
<RowLabeled
|
<RowLabeled
|
||||||
label={
|
label={
|
||||||
|
@ -83,7 +97,22 @@ class AssetInfo extends React.Component {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : 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
|
<RowLabeled
|
||||||
label={
|
label={
|
||||||
<Label value={'Share'} />
|
<Label value={'Share'} />
|
||||||
|
@ -151,13 +180,13 @@ class AssetInfo extends React.Component {
|
||||||
<a
|
<a
|
||||||
className={'link--primary'}
|
className={'link--primary'}
|
||||||
href={`${assetCanonicalUrl}.${fileExt}`}
|
href={`${assetCanonicalUrl}.${fileExt}`}
|
||||||
download={name}
|
download={`${name}.${fileExt}`}
|
||||||
>
|
>
|
||||||
Download
|
Download
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className={'link--primary'}
|
className={'link--primary'}
|
||||||
href={`https://open.lbry.io/${createPermanentURI(asset)}`}
|
href={`https://open.lbry.com/${createPermanentURI(asset)}`}
|
||||||
download={name}
|
download={name}
|
||||||
>
|
>
|
||||||
LBRY URL
|
LBRY URL
|
||||||
|
@ -165,7 +194,7 @@ class AssetInfo extends React.Component {
|
||||||
<a
|
<a
|
||||||
className={'link--primary'}
|
className={'link--primary'}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
href='https://lbry.io/dmca'
|
href={`https://lbry.com/dmca/${claimId}`}
|
||||||
>
|
>
|
||||||
Report
|
Report
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -33,14 +33,14 @@ class NavigationLinks extends React.Component {
|
||||||
const { channelName, showPublish, closedRegistration } = this.props;
|
const { channelName, showPublish, closedRegistration } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className='navigation-links'>
|
<div className='navigation-links'>
|
||||||
{showPublish && <NavLink
|
{/*{showPublish && <NavLink*/}
|
||||||
className='nav-bar-link link--nav'
|
{/* className='nav-bar-link link--nav'*/}
|
||||||
activeClassName='link--nav-active'
|
{/* activeClassName='link--nav-active'*/}
|
||||||
to='/'
|
{/* to='/'*/}
|
||||||
exact
|
{/* exact*/}
|
||||||
>
|
{/*>*/}
|
||||||
Publish
|
{/* Publish*/}
|
||||||
</NavLink>}
|
{/*</NavLink>}*/}
|
||||||
<NavLink
|
<NavLink
|
||||||
className='nav-bar-link link--nav'
|
className='nav-bar-link link--nav'
|
||||||
activeClassName='link--nav-active'
|
activeClassName='link--nav-active'
|
||||||
|
@ -48,24 +48,24 @@ class NavigationLinks extends React.Component {
|
||||||
>
|
>
|
||||||
About
|
About
|
||||||
</NavLink>
|
</NavLink>
|
||||||
{ channelName ? (
|
{/*{ channelName ? (*/}
|
||||||
<NavBarChannelOptionsDropdown
|
{/* <NavBarChannelOptionsDropdown*/}
|
||||||
channelName={this.props.channelName}
|
{/* channelName={this.props.channelName}*/}
|
||||||
handleSelection={this.handleSelection}
|
{/* handleSelection={this.handleSelection}*/}
|
||||||
defaultSelection={this.props.channelName}
|
{/* defaultSelection={this.props.channelName}*/}
|
||||||
VIEW={VIEW}
|
{/* VIEW={VIEW}*/}
|
||||||
LOGOUT={LOGOUT}
|
{/* LOGOUT={LOGOUT}*/}
|
||||||
/>
|
{/* />*/}
|
||||||
) : !closedRegistration && (
|
{/*) : !closedRegistration && (*/}
|
||||||
<NavLink
|
{/* <NavLink*/}
|
||||||
id='nav-bar-login-link'
|
{/* id='nav-bar-login-link'*/}
|
||||||
className='nav-bar-link link--nav'
|
{/* className='nav-bar-link link--nav'*/}
|
||||||
activeClassName='link--nav-active'
|
{/* activeClassName='link--nav-active'*/}
|
||||||
to='/login'
|
{/* to='/login'*/}
|
||||||
>
|
{/* >*/}
|
||||||
Channel
|
{/* Channel*/}
|
||||||
</NavLink>
|
{/* </NavLink>*/}
|
||||||
)}
|
{/*)}*/}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ class PublishDisabledMessage extends React.Component {
|
||||||
<div className={'publish-disabled-message'}>
|
<div className={'publish-disabled-message'}>
|
||||||
<div className={'message'}>
|
<div className={'message'}>
|
||||||
<p className={'text--secondary'}>Publishing is currently disabled.</p>
|
<p className={'text--secondary'}>Publishing is currently disabled.</p>
|
||||||
|
<p className={'text--secondary'}>
|
||||||
|
Try <a className='link--primary' href='https://lbry.tv' target='_blank'>lbry.tv</a>
|
||||||
|
</p>
|
||||||
<p className={'text--secondary'}>{message}</p>
|
<p className={'text--secondary'}>{message}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import {connect} from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {updateMetadata, toggleMetadataInputs} from '../../actions/publish';
|
import { updateMetadata, toggleMetadataInputs } from '../../actions/publish';
|
||||||
import View from './view';
|
import View from './view';
|
||||||
|
|
||||||
const mapStateToProps = ({ publish }) => {
|
const mapStateToProps = ({ publish }) => {
|
||||||
return {
|
return {
|
||||||
showMetadataInputs: publish.showMetadataInputs,
|
showMetadataInputs: publish.showMetadataInputs,
|
||||||
description : publish.metadata.description,
|
description: publish.metadata.description,
|
||||||
license : publish.metadata.license,
|
license: publish.metadata.license,
|
||||||
nsfw : publish.metadata.nsfw,
|
licenseUrl: publish.metadata.licenseUrl,
|
||||||
isUpdate : publish.isUpdate,
|
nsfw: publish.metadata.nsfw,
|
||||||
|
isUpdate: publish.isUpdate,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,10 +18,13 @@ const mapDispatchToProps = dispatch => {
|
||||||
onMetadataChange: (name, value) => {
|
onMetadataChange: (name, value) => {
|
||||||
dispatch(updateMetadata(name, value));
|
dispatch(updateMetadata(name, value));
|
||||||
},
|
},
|
||||||
onToggleMetadataInputs: (value) => {
|
onToggleMetadataInputs: value => {
|
||||||
dispatch(toggleMetadataInputs(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 React from 'react';
|
||||||
import PublishDescriptionInput from '@components/PublishDescriptionInput';
|
import PublishDescriptionInput from '@components/PublishDescriptionInput';
|
||||||
import PublishLicenseInput from '@components/PublishLicenseInput';
|
import PublishLicenseInput from '@components/PublishLicenseInput';
|
||||||
|
import PublishLicenseUrlInput from '@components/PublishLicenseUrlInput';
|
||||||
import PublishNsfwInput from '@components/PublishNsfwInput';
|
import PublishNsfwInput from '@components/PublishNsfwInput';
|
||||||
import ButtonSecondary from '@components/ButtonSecondary';
|
import ButtonSecondary from '@components/ButtonSecondary';
|
||||||
import Row from '@components/Row';
|
|
||||||
|
|
||||||
class PublishMetadataInputs extends React.Component {
|
class PublishMetadataInputs extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -25,22 +25,32 @@ class PublishMetadataInputs extends React.Component {
|
||||||
const name = event.target.name;
|
const name = event.target.name;
|
||||||
const selectedOption = event.target.selectedOptions[0].value;
|
const selectedOption = event.target.selectedOptions[0].value;
|
||||||
this.props.onMetadataChange(name, selectedOption);
|
this.props.onMetadataChange(name, selectedOption);
|
||||||
|
if (name === 'license' && selectedOption !== 'Creative Commons'){
|
||||||
|
this.props.onMetadataChange('licenseUrl', '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const { showMetadataInputs, description, isUpdate, nsfw } = this.props;
|
const { showMetadataInputs, description, isUpdate, nsfw, license, licenseUrl } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{(showMetadataInputs || isUpdate) && (
|
{(showMetadataInputs || isUpdate) && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<PublishDescriptionInput
|
<PublishDescriptionInput
|
||||||
description={this.props.description}
|
description={description}
|
||||||
handleInput={this.handleInput}
|
handleInput={this.handleInput}
|
||||||
/>
|
/>
|
||||||
<PublishLicenseInput
|
<PublishLicenseInput
|
||||||
handleSelect={this.handleSelect}
|
handleSelect={this.handleSelect}
|
||||||
|
license={license}
|
||||||
/>
|
/>
|
||||||
|
{ (this.props.license === 'Creative Commons') && (
|
||||||
|
<PublishLicenseUrlInput
|
||||||
|
handleSelect={this.handleSelect}
|
||||||
|
licenseUrl={licenseUrl}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<PublishNsfwInput
|
<PublishNsfwInput
|
||||||
nsfw={this.props.nsfw}
|
nsfw={nsfw}
|
||||||
handleInput={this.handleInput}
|
handleInput={this.handleInput}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -38,7 +38,7 @@ class PublishStatus extends React.Component {
|
||||||
<ProgressBar size={12} />
|
<ProgressBar size={12} />
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.io/faq/what-is-lbry'>Learn more.</a></p>
|
<p>Curious what magic is happening here? <a className='link--primary' target='blank' href='https://lbry.com/faq/what-is-lbry'>Learn more.</a></p>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class PublishStatus extends React.Component {
|
||||||
<p className={'text--strong'}>{message}</p>
|
<p className={'text--strong'}>{message}</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<p>For help, post the above error text in the #speech channel on the <a className='link--primary' href='https://chat.lbry.io' target='_blank'>lbry discord</a></p>
|
<p>For help, post the above error text in the #speech channel on the <a className='link--primary' href='https://chat.lbry.com' target='_blank'>lbry discord</a></p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {connect} from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {updateMetadata} from '../../actions/publish';
|
import { updateMetadata } from '../../actions/publish';
|
||||||
import View from './view';
|
import View from './view';
|
||||||
|
|
||||||
const mapStateToProps = ({ publish }) => {
|
const mapStateToProps = ({ publish }) => {
|
||||||
|
@ -16,4 +16,7 @@ const mapDispatchToProps = dispatch => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(View);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(View);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ErrorPage from '@pages/ErrorPage';
|
||||||
import ShowAssetLite from '@pages/ShowAssetLite';
|
import ShowAssetLite from '@pages/ShowAssetLite';
|
||||||
import ShowAssetDetails from '@pages/ShowAssetDetails';
|
import ShowAssetDetails from '@pages/ShowAssetDetails';
|
||||||
import ShowChannel from '@pages/ShowChannel';
|
import ShowChannel from '@pages/ShowChannel';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter, Redirect } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CHANNEL,
|
CHANNEL,
|
||||||
|
@ -15,15 +15,24 @@ import {
|
||||||
class ContentPageWrapper extends React.Component {
|
class ContentPageWrapper extends React.Component {
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { onHandleShowPageUri, match, homeChannel } = this.props;
|
const { onHandleShowPageUri, match, homeChannel } = this.props;
|
||||||
onHandleShowPageUri(homeChannel ? { claim: homeChannel } : match.params);
|
//onHandleShowPageUri(homeChannel ? { claim: homeChannel } : match.params);
|
||||||
}
|
}
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
if (nextProps.match.params !== this.props.match.params) {
|
if (nextProps.match.params !== this.props.match.params) {
|
||||||
this.props.onHandleShowPageUri(nextProps.match.params);
|
//this.props.onHandleShowPageUri(nextProps.match.params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const { error, requestType } = this.props;
|
const { error, requestType, match } = this.props;
|
||||||
|
const { params } = match;
|
||||||
|
const { claim, identifier } = params;
|
||||||
|
if (identifier && claim) {
|
||||||
|
return <Redirect to={`https://lbry.tv/${identifier}/${claim}`} />;
|
||||||
|
} else if (identifier) {
|
||||||
|
// return <Redirect to={`https://lbry.tv/${identifier}/`} />
|
||||||
|
} else {
|
||||||
|
return <Redirect to={`https://lbry.tv/${claim}`} />;
|
||||||
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<ErrorPage error={error} />
|
<ErrorPage error={error} />
|
||||||
|
@ -31,13 +40,13 @@ class ContentPageWrapper extends React.Component {
|
||||||
}
|
}
|
||||||
switch (requestType) {
|
switch (requestType) {
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
return <ShowChannel />;
|
// return <ShowChannel />;
|
||||||
case ASSET_LITE:
|
case ASSET_LITE:
|
||||||
return <ShowAssetLite />;
|
// return <ShowAssetLite />;
|
||||||
case ASSET_DETAILS:
|
case ASSET_DETAILS:
|
||||||
return <ShowAssetDetails />;
|
// return <ShowAssetDetails />;
|
||||||
case SPECIAL_ASSET:
|
case SPECIAL_ASSET:
|
||||||
return <ShowChannel />;
|
// return <ShowChannel />;
|
||||||
default:
|
default:
|
||||||
return <p>loading...</p>;
|
return <p>loading...</p>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class EditPage extends React.Component {
|
||||||
onHandleShowPageUri(match.params);
|
onHandleShowPageUri(match.params);
|
||||||
setUpdateTrue();
|
setUpdateTrue();
|
||||||
if (asset) {
|
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);
|
setHasChanged(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class FaqPage extends React.Component {
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>What is spee.ch?</h3>
|
<h3>What is spee.ch?</h3>
|
||||||
<p>Spee.ch is a media-hosting site that reads from and publishes content to the <a href='http://lbry.io/'>LBRY blockchain</a>.</p>
|
<p>Spee.ch is a media-hosting site that reads from and publishes content to the <a href='http://lbry.com/'>LBRY blockchain</a>.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>OK But Why Should I Care?</h3>
|
<h3>OK But Why Should I Care?</h3>
|
||||||
|
@ -29,7 +29,7 @@ class FaqPage extends React.Component {
|
||||||
<p>It’s easy. Drag the image or video file of your choice into the center of the spee.ch homepage.</p>
|
<p>It’s easy. Drag the image or video file of your choice into the center of the spee.ch homepage.</p>
|
||||||
<p>Spee.ch is currently best suited for web optimized MP4 video and standard image filetypes (JPEG, PNG, GIF).</p>
|
<p>Spee.ch is currently best suited for web optimized MP4 video and standard image filetypes (JPEG, PNG, GIF).</p>
|
||||||
<p>If you want to refer to a piece of content repeatedly, or to build a collection of related content, you could create a channel. Channels work both for private collections and for public repositories. There’s more info about how to do this <a href='https://spee.ch/login'>on the channel page</a>.</p>
|
<p>If you want to refer to a piece of content repeatedly, or to build a collection of related content, you could create a channel. Channels work both for private collections and for public repositories. There’s more info about how to do this <a href='https://spee.ch/login'>on the channel page</a>.</p>
|
||||||
<p>Published files will be wiewable and embeddable with any web browser and accesible in the LBRY app. You can also use spee.ch to view free and non-NSFW content published on LBRY network from LBRY app. You just need to replace "lbry://" with "http://spee.ch/" in the URL.</p>
|
<p>Published files will be viewable and embeddable with any web browser and accesible in the LBRY app. You can also use spee.ch to view free and non-NSFW content published on LBRY network from LBRY app. You just need to replace "lbry://" with "http://spee.ch/" in the URL.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>How Long Does Content Stay on Spee.ch?</h3>
|
<h3>How Long Does Content Stay on Spee.ch?</h3>
|
||||||
|
@ -38,7 +38,7 @@ class FaqPage extends React.Component {
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Contribute</h3>
|
<h3>Contribute</h3>
|
||||||
<p>If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a href='https://github.com/lbryio/spee.ch'>github repo</a> and go to town!</p>
|
<p>If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a href='https://github.com/lbryio/spee.ch'>github repo</a> and go to town!</p>
|
||||||
<p>If you want to improve spee.ch, join <a href='https://chat.lbry.io/'>our discord channel</a> or solve one of our <a href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.</p>
|
<p>If you want to improve spee.ch, join <a href='https://chat.lbry.com/'>our discord channel</a> or solve one of our <a href='https://github.com/lbryio/spee.ch/issues'>github issues</a>.</p>
|
||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|
|
@ -7,7 +7,7 @@ const MultisiteContent = () => {
|
||||||
<p className='text--pull-quote'>Introducing Spee.ch Multisite</p>
|
<p className='text--pull-quote'>Introducing Spee.ch Multisite</p>
|
||||||
<p>Hi there! My name is <a href={'https://github.com/billbitt'} target={'_blank'}>Bill</a>, and I’d like to speak with you about Spee.ch. No, not ‘speech,’ ‘<i><a href={'https://spee.ch'} target={'_blank'}>Spee.ch.</a></i>’ You know what, just read on...</p>
|
<p>Hi there! My name is <a href={'https://github.com/billbitt'} target={'_blank'}>Bill</a>, and I’d like to speak with you about Spee.ch. No, not ‘speech,’ ‘<i><a href={'https://spee.ch'} target={'_blank'}>Spee.ch.</a></i>’ You know what, just read on...</p>
|
||||||
<h2>A Little Background</h2>
|
<h2>A Little Background</h2>
|
||||||
<p>Wow, time flies! A little over a year ago Spee.ch was nothing more than a glimmer in the eye of LBRY CEO Jeremy Kaufman. At that time, the <a href={'https://lbry.io/faq/what-is-lbry'} target={'_blank'}>LBRY protocol</a> was still so early in its development, that there were no web-based applications for interacting with the LBRY blockchain. But then, something beautiful happened. On March 29th, 2017, Jeremy sat down with Jack, and together they <a href={'https://www.youtube.com/watch?v=C9LCapt_OYw'} target={'_blank'}>live coded a single-page PHP site</a> that could publish images to the LBRY network. And just like that, Spee.ch was born!</p>
|
<p>Wow, time flies! A little over a year ago Spee.ch was nothing more than a glimmer in the eye of LBRY CEO Jeremy Kaufman. At that time, the <a href={'https://lbry.com/faq/what-is-lbry'} target={'_blank'}>LBRY protocol</a> was still so early in its development, that there were no web-based applications for interacting with the LBRY blockchain. But then, something beautiful happened. On March 29th, 2017, Jeremy sat down with Jack, and together they <a href={'https://www.youtube.com/watch?v=C9LCapt_OYw'} target={'_blank'}>live coded a single-page PHP site</a> that could publish images to the LBRY network. And just like that, Spee.ch was born!</p>
|
||||||
<p>Being that LBRY is an open source project, Jeremy ended the session by inviting community members who were interested in the project to take the reigns and see where Spee.ch could go. I was one of the devs that did just that, and it wasn’t long before I was on a weekly call dedicated to this project with contributors from around the world.</p>
|
<p>Being that LBRY is an open source project, Jeremy ended the session by inviting community members who were interested in the project to take the reigns and see where Spee.ch could go. I was one of the devs that did just that, and it wasn’t long before I was on a weekly call dedicated to this project with contributors from around the world.</p>
|
||||||
<p>At this point in time, the vision for Spee.ch was pretty simple: create a web-based hosting service that used the LBRY network as a database for free image and video sharing. In other words, an ‘imgur on the blockchain.’</p>
|
<p>At this point in time, the vision for Spee.ch was pretty simple: create a web-based hosting service that used the LBRY network as a database for free image and video sharing. In other words, an ‘imgur on the blockchain.’</p>
|
||||||
<h2>Growth</h2>
|
<h2>Growth</h2>
|
||||||
|
@ -41,7 +41,7 @@ const MultisiteContent = () => {
|
||||||
<li>Where: Google Hangouts</li>
|
<li>Where: Google Hangouts</li>
|
||||||
<li>Link: <a href={'https://meet.google.com/aex-ghqg-kcs'} target={'_blank'}>meet.google.com/aex-ghqg-kcs</a></li>
|
<li>Link: <a href={'https://meet.google.com/aex-ghqg-kcs'} target={'_blank'}>meet.google.com/aex-ghqg-kcs</a></li>
|
||||||
<li>System Requirements: If you have a server, please make sure you have MySql, Node and NPM installed. If you need help installing the above, or if you need a server to run your own instance on, please join the Hangout 30 minutes ahead of time and we will help get you set up =]</li>
|
<li>System Requirements: If you have a server, please make sure you have MySql, Node and NPM installed. If you need help installing the above, or if you need a server to run your own instance on, please join the Hangout 30 minutes ahead of time and we will help get you set up =]</li>
|
||||||
<li>Questions: hello@lbry.io</li>
|
<li>Questions: hello@lbry.com</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectAsset } from '../../selectors/show';
|
import { selectAsset, selectDetailsExpanded } from '../../selectors/show';
|
||||||
|
import { toggleDetailsExpanded } from '../../actions/show';
|
||||||
|
|
||||||
import View from './view';
|
import View from './view';
|
||||||
|
|
||||||
const mapStateToProps = ({ show }) => {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
asset: selectAsset(show),
|
asset: selectAsset(state.show),
|
||||||
|
detailsExpanded: selectDetailsExpanded(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(View);
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onToggleDetailsExpanded: value => {
|
||||||
|
dispatch(toggleDetailsExpanded(value));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(View);
|
||||||
|
|
|
@ -11,24 +11,15 @@ class ShowAssetDetails extends React.Component {
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.collapse = this.collapse.bind(this);
|
this.toggleExpandDetails = this.toggleExpandDetails.bind(this);
|
||||||
// this.storageKey = 'vert-split-state-' + this.props.name;
|
|
||||||
// const closed = window && window.localStorage
|
|
||||||
// ? !!window.localStorage.getItem(this.storageKey) : false;
|
|
||||||
const closed = true;
|
|
||||||
this.state = { closed: closed };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse () {
|
toggleExpandDetails () {
|
||||||
this.setState({ closed: !this.state.closed });
|
this.props.onToggleDetailsExpanded(!this.props.detailsExpanded);
|
||||||
// if (window && window.localStorage) {
|
|
||||||
// window.localStorage.setItem(this.storageKey, !this.state.closed);
|
|
||||||
// }
|
|
||||||
// document.querySelectorAll(`[data-name='${this.props.name}']`).forEach(el => el.classList.toggle('closed'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { asset } = this.props;
|
const { asset, detailsExpanded } = this.props;
|
||||||
if (asset) {
|
if (asset) {
|
||||||
const { claimData: { name, blocked } } = asset;
|
const { claimData: { name, blocked } } = asset;
|
||||||
if (!blocked) {
|
if (!blocked) {
|
||||||
|
@ -37,16 +28,16 @@ class ShowAssetDetails extends React.Component {
|
||||||
pageTitle={`${name} - details`}
|
pageTitle={`${name} - details`}
|
||||||
asset={asset}
|
asset={asset}
|
||||||
>
|
>
|
||||||
<div className="asset-main">
|
<div className='asset-main'>
|
||||||
<AssetTitle />
|
<AssetTitle />
|
||||||
<AssetDisplay />
|
<AssetDisplay />
|
||||||
<div>
|
<div>
|
||||||
<button className='collapse-button' onClick={this.collapse}>
|
<button className='collapse-button' onClick={this.toggleExpandDetails}>
|
||||||
{this.state.closed ? <Icon.PlusCircle className='plus-icon' /> : <Icon.MinusCircle />}
|
{detailsExpanded ? <Icon.MinusCircle /> : <Icon.PlusCircle className='plus-icon' /> }
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!this.state.closed && <AssetInfo />}
|
{detailsExpanded && <AssetInfo />}
|
||||||
|
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ const AssetLiteFooter = ({ name, claimId }) => {
|
||||||
return (
|
return (
|
||||||
<SpaceAround>
|
<SpaceAround>
|
||||||
<p className={'text--extra-small'}>
|
<p className={'text--extra-small'}>
|
||||||
<Link className='link--primary' to={`/${claimId}/${name}`}> hosted on spee.ch</Link> via the <a className='link--primary' href={'https://lbry.io/get'} target={'_blank'}>LBRY</a> blockchain
|
<Link className='link--primary' to={`/${claimId}/${name}`}> hosted on spee.ch</Link> via the <a className='link--primary' href={'https://lbry.com/get'} target={'_blank'}>LBRY</a> blockchain
|
||||||
</p>
|
</p>
|
||||||
</SpaceAround>
|
</SpaceAround>
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,15 +13,15 @@ class TosPage extends React.Component {
|
||||||
<Row>
|
<Row>
|
||||||
<h1>Terms of Service</h1>
|
<h1>Terms of Service</h1>
|
||||||
<p>Last updated: September 25, 2018</p>
|
<p>Last updated: September 25, 2018</p>
|
||||||
<p>Please read these Terms of Service ("Terms", "Terms of Service") carefully before using the <a className='link--primary' href='https://spee.ch'>https://spee.ch</a> website (the "Service") operated by <a className='link--primary' href='https://lbry.io'>LBRY INC</a> ("us", "we", or "our").</p>
|
<p>Please read these Terms of Service ("Terms", "Terms of Service") carefully before using the <a className='link--primary' href='https://spee.ch'>https://spee.ch</a> website (the "Service") operated by <a className='link--primary' href='https://lbry.com'>LBRY INC</a> ("us", "we", or "our").</p>
|
||||||
<p>Your access to and use of the Service is conditioned upon your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who wish to access or use the Service.</p>
|
<p>Your access to and use of the Service is conditioned upon your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who wish to access or use the Service.</p>
|
||||||
<p>By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you do not have permission to access the Service.</p>
|
<p>By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you do not have permission to access the Service.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Links To Other Web Sites</h3>
|
<h3>Links To Other Web Sites</h3>
|
||||||
<p>Our Service may contain links to third party web sites or services that are not owned or controlled by <a className='link--primary' href='https://lbry.io'>LBRY INC</a></p>
|
<p>Our Service may contain links to third party web sites or services that are not owned or controlled by <a className='link--primary' href='https://lbry.com'>LBRY INC</a></p>
|
||||||
<p><a className='link--primary' href='https://lbry.io'>LBRY INC</a> has no control over, and assumes no responsibility for the content, privacy policies, or practices of any third party web sites or services. We do not warrant the offerings of any of these entities/individuals or their websites.</p>
|
<p><a className='link--primary' href='https://lbry.com'>LBRY INC</a> has no control over, and assumes no responsibility for the content, privacy policies, or practices of any third party web sites or services. We do not warrant the offerings of any of these entities/individuals or their websites.</p>
|
||||||
<p>You acknowledge and agree that <a className='link--primary' href='https://lbry.io'>LBRY INC</a> shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such third party web sites or services.</p>
|
<p>You acknowledge and agree that <a className='link--primary' href='https://lbry.com'>LBRY INC</a> shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such third party web sites or services.</p>
|
||||||
<p>We strongly advise you to read the terms and conditions and privacy policies of any third party web sites or services that you visit.</p>
|
<p>We strongly advise you to read the terms and conditions and privacy policies of any third party web sites or services that you visit.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
|
@ -35,12 +35,12 @@ class TosPage extends React.Component {
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Limitation Of Liability</h3>
|
<h3>Limitation Of Liability</h3>
|
||||||
<p>In no event shall <a className='link--primary' href='https://lbry.io'>LBRY INC</a>, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use the Service; (ii) any conduct or content of any third party on the Service; (iii) any content obtained from the Service; and (iv) unauthorized access, use or alteration of your transmissions or content, whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.</p>
|
<p>In no event shall <a className='link--primary' href='https://lbry.com'>LBRY INC</a>, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use the Service; (ii) any conduct or content of any third party on the Service; (iii) any content obtained from the Service; and (iv) unauthorized access, use or alteration of your transmissions or content, whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Disclaimer</h3>
|
<h3>Disclaimer</h3>
|
||||||
<p>Your use of the Service is at your sole risk. The Service is provided on an "AS IS" and "AS AVAILABLE" basis. The Service is provided without warranties of any kind, whether express or implied, including, but not limited to, implied warranties of merchantability, fitness for a particular purpose, non-infringement or course of performance.</p>
|
<p>Your use of the Service is at your sole risk. The Service is provided on an "AS IS" and "AS AVAILABLE" basis. The Service is provided without warranties of any kind, whether express or implied, including, but not limited to, implied warranties of merchantability, fitness for a particular purpose, non-infringement or course of performance.</p>
|
||||||
<p><a className='link--primary' href='https://lbry.io'>LBRY INC</a> its subsidiaries, affiliates, and its licensors do not warrant that a) the Service will function uninterrupted, secure or available at any particular time or location; b) any errors or defects will be corrected; c) the Service is free of viruses or other harmful components; or d) the results of using the Service will meet your requirements.</p>
|
<p><a className='link--primary' href='https://lbry.com'>LBRY INC</a> its subsidiaries, affiliates, and its licensors do not warrant that a) the Service will function uninterrupted, secure or available at any particular time or location; b) any errors or defects will be corrected; c) the Service is free of viruses or other harmful components; or d) the results of using the Service will meet your requirements.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Exclusions</h3>
|
<h3>Exclusions</h3>
|
||||||
|
@ -58,7 +58,7 @@ class TosPage extends React.Component {
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<h3>Contact Us</h3>
|
<h3>Contact Us</h3>
|
||||||
<p>If you have any questions about these Terms, please <a className='link--primary' href='mailto:hello@lbry.io'>contact us</a>.</p>
|
<p>If you have any questions about these Terms, please <a className='link--primary' href='mailto:hello@lbry.com'>contact us</a>.</p>
|
||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|
|
@ -19,40 +19,42 @@ if (siteConfig) {
|
||||||
|
|
||||||
// create initial state
|
// create initial state
|
||||||
const initialState = {
|
const initialState = {
|
||||||
disabled : disabledConfig,
|
disabled: disabledConfig,
|
||||||
disabledMessage : disabledMessageConfig,
|
disabledMessage: disabledMessageConfig,
|
||||||
publishInChannel : false,
|
publishInChannel: false,
|
||||||
selectedChannel : LOGIN,
|
selectedChannel: LOGIN,
|
||||||
showMetadataInputs: false,
|
showMetadataInputs: false,
|
||||||
status : {
|
status: {
|
||||||
status : null,
|
status: null,
|
||||||
message: null,
|
message: null,
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
file : null,
|
file: null,
|
||||||
url : null,
|
url: null,
|
||||||
channel: null,
|
channel: null,
|
||||||
},
|
},
|
||||||
file : null,
|
file: null,
|
||||||
claim : '',
|
claim: '',
|
||||||
metadata: {
|
metadata: {
|
||||||
title : '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
license : '',
|
license: '',
|
||||||
nsfw : false,
|
licenseUrl: '',
|
||||||
|
tags: [],
|
||||||
},
|
},
|
||||||
isUpdate : false,
|
isUpdate: false,
|
||||||
hasChanged: false,
|
hasChanged: false,
|
||||||
thumbnail : null,
|
thumbnail: null,
|
||||||
thumbnailChannel,
|
thumbnailChannel,
|
||||||
thumbnailChannelId,
|
thumbnailChannelId,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action) {
|
export default function(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actions.FILE_SELECTED:
|
case actions.FILE_SELECTED:
|
||||||
return Object.assign({}, state.isUpdate ? state : initialState, { // note: clears to initial state
|
return Object.assign({}, state.isUpdate ? state : initialState, {
|
||||||
file : action.data,
|
// note: clears to initial state
|
||||||
|
file: action.data,
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
});
|
});
|
||||||
case actions.FILE_CLEAR:
|
case actions.FILE_CLEAR:
|
||||||
|
@ -66,13 +68,13 @@ export default function (state = initialState, action) {
|
||||||
});
|
});
|
||||||
case actions.CLAIM_UPDATE:
|
case actions.CLAIM_UPDATE:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
claim : action.data,
|
claim: action.data,
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
});
|
});
|
||||||
case actions.SET_PUBLISH_IN_CHANNEL:
|
case actions.SET_PUBLISH_IN_CHANNEL:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
publishInChannel: action.channel,
|
publishInChannel: action.channel,
|
||||||
hasChanged : true,
|
hasChanged: true,
|
||||||
});
|
});
|
||||||
case actions.PUBLISH_STATUS_UPDATE:
|
case actions.PUBLISH_STATUS_UPDATE:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
|
@ -96,7 +98,7 @@ export default function (state = initialState, action) {
|
||||||
case actions.THUMBNAIL_NEW:
|
case actions.THUMBNAIL_NEW:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
thumbnail : action.data,
|
thumbnail: action.data,
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
};
|
};
|
||||||
case actions.SET_UPDATE_TRUE:
|
case actions.SET_UPDATE_TRUE:
|
||||||
|
@ -112,4 +114,4 @@ export default function (state = initialState, action) {
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -4,19 +4,20 @@ import { LOCAL_CHECK, ERROR } from '../constants/asset_display_states';
|
||||||
const initialState = {
|
const initialState = {
|
||||||
request: {
|
request: {
|
||||||
error: null,
|
error: null,
|
||||||
type : null,
|
type: null,
|
||||||
id : null,
|
id: null,
|
||||||
},
|
},
|
||||||
requestList : {},
|
requestList: {},
|
||||||
channelList : {},
|
channelList: {},
|
||||||
assetList : {},
|
assetList: {},
|
||||||
displayAsset: {
|
displayAsset: {
|
||||||
error : null,
|
error: null,
|
||||||
status: LOCAL_CHECK,
|
status: LOCAL_CHECK,
|
||||||
},
|
},
|
||||||
|
detailsExpanded: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action) {
|
export default function(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
// handle request
|
// handle request
|
||||||
case actions.REQUEST_ERROR:
|
case actions.REQUEST_ERROR:
|
||||||
|
@ -29,7 +30,7 @@ export default function (state = initialState, action) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
request: Object.assign({}, state.request, {
|
request: Object.assign({}, state.request, {
|
||||||
type: action.data.requestType,
|
type: action.data.requestType,
|
||||||
id : action.data.requestId,
|
id: action.data.requestId,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
// store requests
|
// store requests
|
||||||
|
@ -38,7 +39,7 @@ export default function (state = initialState, action) {
|
||||||
requestList: Object.assign({}, state.requestList, {
|
requestList: Object.assign({}, state.requestList, {
|
||||||
[action.data.id]: {
|
[action.data.id]: {
|
||||||
error: action.data.error,
|
error: action.data.error,
|
||||||
key : action.data.key,
|
key: action.data.key,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -47,11 +48,11 @@ export default function (state = initialState, action) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
assetList: Object.assign({}, state.assetList, {
|
assetList: Object.assign({}, state.assetList, {
|
||||||
[action.data.id]: {
|
[action.data.id]: {
|
||||||
error : action.data.error,
|
error: action.data.error,
|
||||||
name : action.data.name,
|
name: action.data.name,
|
||||||
claimId : action.data.claimId,
|
claimId: action.data.claimId,
|
||||||
shortId : action.data.shortId,
|
shortId: action.data.shortId,
|
||||||
claimData : action.data.claimData,
|
claimData: action.data.claimData,
|
||||||
claimViews: action.data.claimViews,
|
claimViews: action.data.claimViews,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -76,7 +77,7 @@ export default function (state = initialState, action) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
assetList : newAssetList,
|
assetList: newAssetList,
|
||||||
channelList: {
|
channelList: {
|
||||||
...state.channelList,
|
...state.channelList,
|
||||||
[channelId]: {
|
[channelId]: {
|
||||||
|
@ -107,9 +108,9 @@ export default function (state = initialState, action) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
channelList: Object.assign({}, state.channelList, {
|
channelList: Object.assign({}, state.channelList, {
|
||||||
[action.data.id]: {
|
[action.data.id]: {
|
||||||
name : action.data.name,
|
name: action.data.name,
|
||||||
longId : action.data.longId,
|
longId: action.data.longId,
|
||||||
shortId : action.data.shortId,
|
shortId: action.data.shortId,
|
||||||
claimsData: action.data.claimsData,
|
claimsData: action.data.claimsData,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -117,9 +118,13 @@ export default function (state = initialState, action) {
|
||||||
case actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED:
|
case actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
channelList: Object.assign({}, state.channelList, {
|
channelList: Object.assign({}, state.channelList, {
|
||||||
[action.data.channelListId]: Object.assign({}, state.channelList[action.data.channelListId], {
|
[action.data.channelListId]: Object.assign(
|
||||||
|
{},
|
||||||
|
state.channelList[action.data.channelListId],
|
||||||
|
{
|
||||||
claimsData: action.data.claimsData,
|
claimsData: action.data.claimsData,
|
||||||
}),
|
}
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
// display an asset
|
// display an asset
|
||||||
|
@ -132,10 +137,15 @@ export default function (state = initialState, action) {
|
||||||
case actions.DISPLAY_ASSET_ERROR:
|
case actions.DISPLAY_ASSET_ERROR:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
displayAsset: Object.assign({}, state.displayAsset, {
|
displayAsset: Object.assign({}, state.displayAsset, {
|
||||||
error : action.data,
|
error: action.data,
|
||||||
status: ERROR,
|
status: ERROR,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
case actions.TOGGLE_DETAILS_EXPANDED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
detailsExpanded: action.data,
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,19 @@ import { updatePublishStatus, clearFile } from '../actions/publish';
|
||||||
import { removeAsset } from '../actions/show';
|
import { removeAsset } from '../actions/show';
|
||||||
import { doAbandonClaim } from '../api/assetApi';
|
import { doAbandonClaim } from '../api/assetApi';
|
||||||
|
|
||||||
function * abandonClaim (action) {
|
function* abandonClaim(action) {
|
||||||
const { claimData, history } = action.data;
|
const { claimData, history } = action.data;
|
||||||
const { claimId } = claimData;
|
const { outpoint } = claimData;
|
||||||
|
|
||||||
const confirm = window.confirm('Are you sure you want to abandon this claim? This action cannot be undone.');
|
const confirm = window.confirm(
|
||||||
|
'Are you sure you want to abandon this claim? This action cannot be undone.'
|
||||||
|
);
|
||||||
if (!confirm) return;
|
if (!confirm) return;
|
||||||
|
|
||||||
yield put(updatePublishStatus(publishStates.ABANDONING, 'Your claim is being abandoned...'));
|
yield put(updatePublishStatus(publishStates.ABANDONING, 'Your claim is being abandoned...'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield call(doAbandonClaim, claimId);
|
yield call(doAbandonClaim, outpoint);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return console.log('abandon error:', error.message);
|
return console.log('abandon error:', error.message);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +27,6 @@ function * abandonClaim (action) {
|
||||||
return history.push('/');
|
return history.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function * watchAbandonClaim () {
|
export function* watchAbandonClaim() {
|
||||||
yield takeLatest(actions.ABANDON_CLAIM, abandonClaim);
|
yield takeLatest(actions.ABANDON_CLAIM, abandonClaim);
|
||||||
};
|
}
|
||||||
|
|
|
@ -9,11 +9,22 @@ import { selectShowState, selectAsset } from '../selectors/show';
|
||||||
import { validateChannelSelection, validateNoPublishErrors } from '../utils/validate';
|
import { validateChannelSelection, validateNoPublishErrors } from '../utils/validate';
|
||||||
import { createPublishMetadata, createPublishFormData, createThumbnailUrl } from '../utils/publish';
|
import { createPublishMetadata, createPublishFormData, createThumbnailUrl } from '../utils/publish';
|
||||||
import { makePublishRequestChannel } from '../channels/publish';
|
import { makePublishRequestChannel } from '../channels/publish';
|
||||||
|
// yep
|
||||||
function * publishFile (action) {
|
function* publishFile(action) {
|
||||||
const { history } = action.data;
|
const { history } = action.data;
|
||||||
const publishState = yield select(selectPublishState);
|
const publishState = yield select(selectPublishState);
|
||||||
const { publishInChannel, selectedChannel, file, claim, metadata, thumbnailChannel, thumbnailChannelId, thumbnail, isUpdate, error: publishToolErrors } = publishState;
|
const {
|
||||||
|
publishInChannel,
|
||||||
|
selectedChannel,
|
||||||
|
file,
|
||||||
|
claim,
|
||||||
|
metadata,
|
||||||
|
thumbnailChannel,
|
||||||
|
thumbnailChannelId,
|
||||||
|
thumbnail,
|
||||||
|
isUpdate,
|
||||||
|
error: publishToolErrors,
|
||||||
|
} = publishState;
|
||||||
const { loggedInChannel } = yield select(selectChannelState);
|
const { loggedInChannel } = yield select(selectChannelState);
|
||||||
const { host } = yield select(selectSiteState);
|
const { host } = yield select(selectSiteState);
|
||||||
|
|
||||||
|
@ -39,7 +50,7 @@ function * publishFile (action) {
|
||||||
// create metadata
|
// create metadata
|
||||||
publishMetadata = createPublishMetadata(
|
publishMetadata = createPublishMetadata(
|
||||||
isUpdate ? asset.name : claim,
|
isUpdate ? asset.name : claim,
|
||||||
isUpdate ? {type: asset.claimData.contentType} : file,
|
isUpdate ? { type: asset.claimData.contentType } : file,
|
||||||
metadata,
|
metadata,
|
||||||
publishInChannel,
|
publishInChannel,
|
||||||
selectedChannel
|
selectedChannel
|
||||||
|
@ -49,7 +60,12 @@ function * publishFile (action) {
|
||||||
}
|
}
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
// add thumbnail to publish metadata
|
// add thumbnail to publish metadata
|
||||||
publishMetadata['thumbnail'] = createThumbnailUrl(thumbnailChannel, thumbnailChannelId, claim, host);
|
publishMetadata['thumbnail'] = createThumbnailUrl(
|
||||||
|
thumbnailChannel,
|
||||||
|
thumbnailChannelId,
|
||||||
|
claim,
|
||||||
|
host
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// create form data for main publish
|
// create form data for main publish
|
||||||
publishFormData = createPublishFormData(file, thumbnail, publishMetadata);
|
publishFormData = createPublishFormData(file, thumbnail, publishMetadata);
|
||||||
|
@ -57,7 +73,7 @@ function * publishFile (action) {
|
||||||
publishChannel = yield call(makePublishRequestChannel, publishFormData, isUpdate);
|
publishChannel = yield call(makePublishRequestChannel, publishFormData, isUpdate);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const {loadStart, progress, load, success, error: publishError} = yield take(publishChannel);
|
const { loadStart, progress, load, success, error: publishError } = yield take(publishChannel);
|
||||||
if (publishError) {
|
if (publishError) {
|
||||||
return yield put(updatePublishStatus(publishStates.FAILED, publishError.message));
|
return yield put(updatePublishStatus(publishStates.FAILED, publishError.message));
|
||||||
}
|
}
|
||||||
|
@ -67,7 +83,7 @@ function * publishFile (action) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'ASSET_UPDATE_CLAIMDATA',
|
type: 'ASSET_UPDATE_CLAIMDATA',
|
||||||
data: {
|
data: {
|
||||||
id : `a#${success.data.name}#${success.data.claimId}`,
|
id: `a#${success.data.name}#${success.data.claimId}`,
|
||||||
claimData: success.data.claimData,
|
claimData: success.data.claimData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -91,6 +107,6 @@ function * publishFile (action) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function * watchPublishStart () {
|
export function* watchPublishStart() {
|
||||||
yield takeLatest(actions.PUBLISH_START, publishFile);
|
yield takeLatest(actions.PUBLISH_START, publishFile);
|
||||||
};
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ export const selectAsset = show => {
|
||||||
return asset;
|
return asset;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectShowState = (state) => {
|
export const selectShowState = state => {
|
||||||
return state.show;
|
return state.show;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const selectDetailsExpanded = state => {
|
||||||
|
return state.show.detailsExpanded;
|
||||||
|
};
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
export const createPublishMetadata = (claim, { type }, { title, description, license, nsfw }, publishInChannel, selectedChannel) => {
|
export const createPublishMetadata = (
|
||||||
|
claim,
|
||||||
|
{ type },
|
||||||
|
{ title, description, license, licenseUrl, nsfw },
|
||||||
|
publishInChannel,
|
||||||
|
selectedChannel
|
||||||
|
) => {
|
||||||
|
// this metadata stuff needs to be removed...
|
||||||
let metadata = {
|
let metadata = {
|
||||||
name: claim,
|
name: claim,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
license,
|
license,
|
||||||
|
licenseUrl,
|
||||||
nsfw,
|
nsfw,
|
||||||
type,
|
type,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Configure your own spee.ch
|
# Configure your own spee.ch
|
||||||
|
|
||||||
_note: this guide assumes you have done the [quickstart](https://github.com/lbryio/spee.ch/blob/readme-update/README.md) or [fullstart](https://github.com/lbryio/spee.ch/blob/readme-update/fullstart.md) guide and have a working spee.ch server_
|
_note: this guide assumes you have done the [quickstart](https://github.com/lbryio/spee.ch/blob/master/README.md) or [fullstart](https://github.com/lbryio/spee.ch/blob/master/fullstart.md) guide and have a working spee.ch server_
|
||||||
|
|
||||||
## Custom Components
|
## Custom Components
|
||||||
The components used by spee.ch are taken from the `client/` folder, but you can override those components by defining your own in the `site/custom/` folder.
|
The components used by spee.ch are taken from the `client/` folder, but you can override those components by defining your own in the `site/custom/` folder.
|
||||||
|
|
|
@ -26,7 +26,6 @@ PUBLISHING:
|
||||||
|
|
||||||
"primaryClaimAddress": null, - generally supplied by your lbrynet sdk
|
"primaryClaimAddress": null, - generally supplied by your lbrynet sdk
|
||||||
"uploadDirectory": "/home/lbry/Uploads", - lbrynet sdk will know your uploads are here
|
"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.
|
"thumbnailChannel": null, - when publishing non-image content, thumbnails will go here.
|
||||||
"thumbnailChannelId": null,
|
"thumbnailChannelId": null,
|
||||||
"additionalClaimAddresses": [],
|
"additionalClaimAddresses": [],
|
||||||
|
@ -39,12 +38,24 @@ PUBLISHING:
|
||||||
"publishingChannelWhitelist": [],
|
"publishingChannelWhitelist": [],
|
||||||
"channelClaimBidAmount": "0.1", - When creating a channel, how much you deposit to control the name
|
"channelClaimBidAmount": "0.1", - When creating a channel, how much you deposit to control the name
|
||||||
"fileClaimBidAmount": "0.01", - When publishing content, how much you deposit to control the name
|
"fileClaimBidAmount": "0.01", - When publishing content, how much you deposit to control the name
|
||||||
"maxSizeImage": 10000000, - You may not want people uploading 50GB files. 1000000 = 1MB
|
"fileSizeLimits": {
|
||||||
"maxSizeGif": 50000000,
|
"image": 50000000,
|
||||||
"maxSizeVideo": 50000000
|
"video": 50000000,
|
||||||
|
"audio": 50000000,
|
||||||
|
"text": 10000000,
|
||||||
|
"model": 50000000,
|
||||||
|
"application": 500000000,
|
||||||
|
"customByContentType": {
|
||||||
|
"application/octet-stream": 50000000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SERVING:
|
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": {
|
"markdownSettings": {
|
||||||
"skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~
|
"skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~
|
||||||
"escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly
|
"escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly
|
||||||
|
@ -80,9 +91,6 @@ SERVING:
|
||||||
"html", - potentially DANGEROUS, intended for `serveOnlyApproved = true` environments, includes iframes, divs.
|
"html", - potentially DANGEROUS, intended for `serveOnlyApproved = true` environments, includes iframes, divs.
|
||||||
"parsedHtml"
|
"parsedHtml"
|
||||||
],
|
],
|
||||||
"disallowedTypesMain": [], - not implemented
|
|
||||||
"disallowedTypesDescriptions": ["image", "html"], - not implemented
|
|
||||||
"disallowedTypesExample": ["image", "html"] - not implemented
|
|
||||||
},
|
},
|
||||||
"customFileExtensions": { - suggest a file extension for experimental content types you may be publishing
|
"customFileExtensions": { - suggest a file extension for experimental content types you may be publishing
|
||||||
"application/example-type": "example"
|
"application/example-type": "example"
|
||||||
|
|
15
docs/setup/conf/lbrynet/lbrynet.service.example
Normal file
15
docs/setup/conf/lbrynet/lbrynet.service.example
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description="LBRYnet daemon"
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment="HOME=/home/lbry"
|
||||||
|
ExecStart=/opt/lbry/lbrynet start
|
||||||
|
User=lbry
|
||||||
|
Group=lbry
|
||||||
|
Restart=on-failure
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
16
docs/setup/conf/lbrynet/lbrynet.service.template
Normal file
16
docs/setup/conf/lbrynet/lbrynet.service.template
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[Unit]
|
||||||
|
Description="LBRYnet daemon"
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
# Change environment to /home/{{USERNAME}}
|
||||||
|
[Service]
|
||||||
|
Environment="HOME=/home/{{USERNAME}}"
|
||||||
|
ExecStart=/opt/lbry/lbrynet start
|
||||||
|
User={{USERNAME}}
|
||||||
|
Group={{USERNAME}}
|
||||||
|
Restart=on-failure
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
* Lbrynet DAEMON started on ports 3333 and 4444
|
* Lbrynet DAEMON started on ports 3333 and 4444
|
||||||
* Spee.ch started on port 3000
|
* Spee.ch started on port 3000
|
||||||
|
|
||||||
|
_note: throughout this guide you'll be replacing `{{xyz}}` with `yourvalue` omitting the brackets_
|
||||||
|
|
||||||
# 1. Setup OS and install dependencies
|
# 1. Setup OS and install dependencies
|
||||||
## OS
|
## OS
|
||||||
|
|
||||||
|
@ -36,26 +38,27 @@ As root# _create user and add to sudo group_
|
||||||
su - username
|
su - username
|
||||||
```
|
```
|
||||||
As username: *paste public key in authorized\_keys*
|
As username: *paste public key in authorized\_keys*
|
||||||
```
|
|
||||||
`cd`
|
`cd`
|
||||||
|
|
||||||
`mkdir .ssh`
|
`mkdir .ssh`
|
||||||
|
|
||||||
`nano ~/.ssh/authorized_keys`
|
`nano ~/.ssh/authorized_keys`
|
||||||
```
|
|
||||||
|
|
||||||
### Prep
|
### Prep
|
||||||
|
|
||||||
Log in as username@domainname or username@ip_address
|
ssh to username@domainname or username@ip_address
|
||||||
|
|
||||||
`sudo apt-get update -y`
|
```
|
||||||
|
sudo apt-get update -y
|
||||||
`ulimit -n 8192`
|
ulimit -n 8192
|
||||||
|
wget -qO- https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||||
`wget -qO- https://deb.nodesource.com/setup_8.x | sudo -E bash -`
|
```
|
||||||
|
|
||||||
|
|
||||||
## Git, Curl, Tmux, Unzip, ffmpeg, Node
|
## Git, Curl, Unzip, ffmpeg, imagemagick, Node
|
||||||
|
|
||||||
`sudo apt-get install git curl tmux unzip ffmpeg nodejs -y`
|
`sudo apt-get install git curl unzip ffmpeg nodejs imagemagick -y`
|
||||||
|
|
||||||
## Clone speech either from your own fork, or from the lbryio/spee.ch repo.
|
## Clone speech either from your own fork, or from the lbryio/spee.ch repo.
|
||||||
|
|
||||||
|
@ -78,24 +81,29 @@ Log in as username@domainname or username@ip_address
|
||||||
`chmod 750 -R ~/spee.ch/docs/setup`
|
`chmod 750 -R ~/spee.ch/docs/setup`
|
||||||
|
|
||||||
# 2 Secure the UFW firewall
|
# 2 Secure the UFW firewall
|
||||||
|
|
||||||
## UFW
|
## UFW
|
||||||
|
|
||||||
`sudo ~/spee.ch/docs/setup/scripts/firewall.sh`
|
`sudo ~/spee.ch/docs/setup/scripts/firewall.sh`
|
||||||
|
|
||||||
|
_if your distro isn't vanilla ubuntu 16 or 18, you may have to install it_
|
||||||
|
|
||||||
# 3 Install Caddy to handle https and reverse proxy
|
# 3 Install Caddy to handle https and reverse proxy
|
||||||
|
|
||||||
## Get Caddy
|
## Get Caddy
|
||||||
|
|
||||||
`curl https://getcaddy.com | sudo bash -s personal`
|
`curl https://getcaddy.com | sudo bash -s personal`
|
||||||
|
|
||||||
## Set up Caddy reverse proxy and ssl
|
## Set up Caddy reverse proxy and ssl
|
||||||
|
|
||||||
`sudo mkdir -p /opt/caddy/logs/`
|
_Make Caddy's folders, copy the template, edit the Caddyfile, copy the caddyfile to its folder._
|
||||||
|
|
||||||
`sudo mkdir -p /opt/caddy/store/`
|
```
|
||||||
|
sudo mkdir -p /opt/caddy/logs/
|
||||||
`cp ~/spee.ch/docs/setup/conf/caddy/Caddyfile.template ~/spee.ch/docs/setup/conf/caddy/Caddyfile`
|
sudo mkdir -p /opt/caddy/store/
|
||||||
|
cp ~/spee.ch/docs/setup/conf/caddy/Caddyfile.template ~/spee.ch/docs/setup/conf/caddy/Caddyfile
|
||||||
`nano ~/spee.ch/docs/setup/conf/caddy/Caddyfile`
|
nano ~/spee.ch/docs/setup/conf/caddy/Caddyfile
|
||||||
|
```
|
||||||
|
|
||||||
( Change {{EXAMPLE.COM}} to YOURDOMAIN.COM )
|
( Change {{EXAMPLE.COM}} to YOURDOMAIN.COM )
|
||||||
|
|
||||||
|
@ -103,19 +111,15 @@ Log in as username@domainname or username@ip_address
|
||||||
|
|
||||||
## Set up Caddy to run as systemd service
|
## Set up Caddy to run as systemd service
|
||||||
|
|
||||||
`sudo cp ~/spee.ch/docs/setup/conf/caddy/caddy.service /etc/systemd/system/caddy.service`
|
```
|
||||||
|
sudo cp ~/spee.ch/docs/setup/conf/caddy/caddy.service /etc/systemd/system/caddy.service
|
||||||
`sudo chmod 644 /etc/systemd/system/caddy.service`
|
sudo chmod 644 /etc/systemd/system/caddy.service
|
||||||
|
sudo chown -R www-data:www-data /opt/caddy/
|
||||||
`sudo chown -R www-data:www-data /opt/caddy/`
|
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy
|
||||||
|
sudo systemctl daemon-reload
|
||||||
`sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy`
|
sudo systemctl start caddy
|
||||||
|
sudo systemctl status caddy
|
||||||
`sudo systemctl daemon-reload`
|
```
|
||||||
|
|
||||||
`sudo systemctl start caddy`
|
|
||||||
|
|
||||||
`sudo systemctl status caddy`
|
|
||||||
|
|
||||||
`q` exits
|
`q` exits
|
||||||
|
|
||||||
|
@ -151,7 +155,7 @@ Log in as username@domainname or username@ip_address
|
||||||
|
|
||||||
mysql>
|
mysql>
|
||||||
|
|
||||||
`ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_mysql_password';`
|
`ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword123';`
|
||||||
|
|
||||||
mysql>
|
mysql>
|
||||||
|
|
||||||
|
@ -163,57 +167,110 @@ Log in as username@domainname or username@ip_address
|
||||||
|
|
||||||
`mysql -u root -p` and then entering your_mysql_password should give you the mysql> shell
|
`mysql -u root -p` and then entering your_mysql_password should give you the mysql> shell
|
||||||
|
|
||||||
# 5 Get Lbrynet Daemon
|
# 5 Get Lbrynet SDK Daemon
|
||||||
|
|
||||||
## Start tmux
|
## Get the SDK
|
||||||
|
|
||||||
tmux allows you to run multiple things in different sessions. Useful for manually starting daemons and watching its console logs.
|
We'll be putting it in /opt/lbry.
|
||||||
|
|
||||||
`tmux`
|
`sudo mkdir /opt/lbry`
|
||||||
* `Ctrl+b`, then `d` detaches leaving session running.
|
|
||||||
* `tmux`, reenters tmux, then
|
|
||||||
* `Ctrl+b`, `(` goes back to through sessions
|
|
||||||
|
|
||||||
## Get the daemon
|
`sudo wget -O /opt/lbry/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip`
|
||||||
`wget -O ~/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip`
|
|
||||||
|
|
||||||
`unzip -o -u ~/latest_daemon.zip`
|
`sudo unzip -o -u /opt/lbry/latest_daemon.zip -d /opt/lbry`
|
||||||
|
|
||||||
## Start the daemon
|
## Set up lbrynet to run as systemd service
|
||||||
`./lbrynet start`
|
|
||||||
|
|
||||||
## Detatch tmux session
|
We'll soon update the setup scripts. Meanwhile, here's an example lbrynet.service file. Again, fully replace {{USERNAME}}
|
||||||
`Control + b`, then `d`
|
|
||||||
|
|
||||||
* `tmux` if you want to get back into tmux
|
```
|
||||||
|
[Unit]
|
||||||
|
Description="LBRYnet daemon"
|
||||||
|
After=network.target
|
||||||
|
|
||||||
* `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output
|
# Replace {{USERNAME}} with your username, e.g. `bob` or `speechuser`
|
||||||
|
[Service]
|
||||||
|
Environment="HOME=/home/{{USERNAME}}"
|
||||||
|
ExecStart=/opt/lbry/lbrynet start
|
||||||
|
User={{USERNAME}}
|
||||||
|
Group={{USERNAME}}
|
||||||
|
Restart=on-failure
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
`tmux`
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
```
|
||||||
|
`sudo nano /etc/systemd/system/lbrynet.service`
|
||||||
|
|
||||||
|
|
||||||
|
Then paste the above into the file and edit replacing {{USERNAME}} with yours.
|
||||||
|
|
||||||
|
Finally do the following.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo chmod 644 /etc/systemd/system/lbrynet.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl start lbrynet
|
||||||
|
sudo systemctl status lbrynet
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll find your lbrynet logs in ~/.local/share/lbry/lbrynet/lbrynet.log
|
||||||
|
|
||||||
|
Let's make our lives easier and link /opt/lbry/lbrynet in /usr/local/bin
|
||||||
|
|
||||||
|
`sudo ln -s /opt/lbry/lbrynet /usr/local/bin/lbrynet`
|
||||||
|
|
||||||
|
Now we can `lbrynet` without `/opt/lbry`. Let's make sure we're back in our home directory. `cd`
|
||||||
|
|
||||||
|
## Customize SDK settings
|
||||||
|
|
||||||
|
These settings will prevent you and your users from spending your server's LBC on paid content. Full documentation is [here](https://lbry.tech/resources/daemon-settings).
|
||||||
|
|
||||||
|
~$
|
||||||
|
|
||||||
|
`cd ~/.local/share/lbry/lbrynet`
|
||||||
|
|
||||||
|
`nano daemon_settings.yml`
|
||||||
|
|
||||||
|
copy and paste in the following code (Ctrl+Shift V)
|
||||||
|
|
||||||
|
_upnp is unnecessary for a vps but may be useful behind a properly configured NAT_
|
||||||
|
|
||||||
|
```
|
||||||
|
run_reflector_server: false
|
||||||
|
max_key_fee: {amount: 0, currency: LBC}
|
||||||
|
use_upnp: false
|
||||||
|
auto_re_reflect_interval: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
`CONTROL+O` then `CONTROL+X` to save and exit
|
||||||
|
|
||||||
|
Restart lbrynet sdk:
|
||||||
|
|
||||||
|
`sudo systemctl restart lbrynet`
|
||||||
|
|
||||||
|
`sudo systemctl status lbrynet`
|
||||||
|
|
||||||
_note: `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output_
|
|
||||||
|
|
||||||
## Display wallet address to which to send 5+ LBC.
|
## Display wallet address to which to send 5+ LBC.
|
||||||
|
|
||||||
_note: These commands work when `./lbrynet start` is already running in another tmux session_
|
_note: These commands work when `lbrynet` is already running_
|
||||||
|
|
||||||
`./lbrynet commands` to check out the current commands
|
`lbrynet commands` to check out the current commands
|
||||||
|
|
||||||
`./lbrynet address_list` to get your wallet address
|
`lbrynet address list` to get your wallet address
|
||||||
|
|
||||||
`Ctrl + Shift + C` after highlighting an address to copy.
|
`Ctrl + Shift + C` after highlighting an address to copy.
|
||||||
|
|
||||||
Use a LBRY app or daemon to send LBC to the address. Sending LBC may take a few seconds or longer.
|
Use a LBRY app or daemon to send LBC to the address. Sending LBC may take a few seconds or longer.
|
||||||
|
|
||||||
`./lbrynet account_balance` to check your balance after you've sent LBC.
|
`lbrynet account balance` to check your balance after you've sent LBC.
|
||||||
|
|
||||||
## Optional/Production: Set up lbrynet to run as a systemd service
|
|
||||||
|
|
||||||
`//coming soon`
|
|
||||||
|
|
||||||
# 6 Set up spee.ch
|
# 6 Set up spee.ch
|
||||||
|
|
||||||
## Build it
|
## Build it
|
||||||
|
|
||||||
`cd spee.ch`
|
`cd spee.ch`
|
||||||
|
|
||||||
~/spee.ch:
|
~/spee.ch:
|
||||||
|
@ -234,7 +291,8 @@ tmux allows you to run multiple things in different sessions. Useful for manuall
|
||||||
* Port: 3000
|
* Port: 3000
|
||||||
* Site Title: Your Site Name
|
* Site Title: Your Site Name
|
||||||
* Enter your site's domain name: https://example.com or http://localhost:3000
|
* Enter your site's domain name: https://example.com or http://localhost:3000
|
||||||
* Enter a directory where uploads should be stored: (/home/lbry/Uploads)
|
* Enter a directory where uploads should be stored: (/home/{{username}}/Uploads) *
|
||||||
|
_* if you're not sure, `pwd`_
|
||||||
|
|
||||||
`npm run build` (or `npm run dev` to build for developing)
|
`npm run build` (or `npm run dev` to build for developing)
|
||||||
|
|
||||||
|
@ -247,15 +305,34 @@ tmux allows you to run multiple things in different sessions. Useful for manuall
|
||||||
# 7 Production
|
# 7 Production
|
||||||
|
|
||||||
## pm2 to keep your speech app running
|
## pm2 to keep your speech app running
|
||||||
```
|
|
||||||
npm install -g pm2
|
If your server is running in the terminal from the last section, `Control+C` it.
|
||||||
```
|
|
||||||
|
`sudo npm install -g pm2` _There are tutorials online for avoiding sudo for npm i -g_
|
||||||
|
|
||||||
|
`cd spee.ch`
|
||||||
|
|
||||||
|
`pm2 start npm --name speech -- run start`
|
||||||
|
|
||||||
|
While pm2 installed this way will restart the server, it will not rebuild it on changes. You'll do that manually as discussed before.
|
||||||
|
|
||||||
### 7 Maintenance Procedures
|
### 7 Maintenance Procedures
|
||||||
|
|
||||||
#### Change daemon
|
#### Update sdk daemon
|
||||||
* backup wallet (private keys!) to a safe place
|
|
||||||
* wget daemon from https://github.com/lbryio/lbry/releases
|
* Backup wallet (private keys!) to a safe place. It should be in ~/.local/share/lbry/lbryum/wallets.
|
||||||
* wget -O ~/your_name_daemon.zip https://your_copied_file_path.zip
|
* `lbrynet stop`
|
||||||
* rm ./lbrynet
|
* Following the instructions in 5: Get the SDK will rename the old daemon and give you the new one.
|
||||||
* unzip -o -u ~/your_name_daemon.zip
|
* `lbrynet start`
|
||||||
|
* `lbrynet version`
|
||||||
|
* `lbrynet account balance`
|
||||||
|
|
||||||
|
#### Update speech
|
||||||
|
|
||||||
|
* Read the release notes to see if there are any breaking changes, address them
|
||||||
|
* `pm2 stop speech`
|
||||||
|
* `git pull origin release` (assuming you cloned release)
|
||||||
|
* `npm i` if necessary
|
||||||
|
* `npm run build`
|
||||||
|
* `pm2 start speech`
|
||||||
|
* Have an exotic energy drink
|
||||||
|
|
77
fullstart.md
77
fullstart.md
|
@ -1,51 +1,55 @@
|
||||||
# Create Your Own Spee.ch!
|
# Create Your Own Spee.ch!
|
||||||
|
|
||||||
## 1. Prerequisites
|
## 1. Prerequisites
|
||||||
|
|
||||||
### You will need the following tools installed
|
### You will need the following tools installed
|
||||||
|
|
||||||
* Node (v8 LTS).
|
- Node (v8 LTS).
|
||||||
* Make sure you install from the **Node** website [link](https://nodejs.org/en/download/).
|
- Make sure you install from the **Node** website [link](https://nodejs.org/en/download/).
|
||||||
* npm (should come installed with Node).
|
- npm (should come installed with Node).
|
||||||
* Git
|
- Git
|
||||||
* Curl
|
- Curl
|
||||||
* Tmux
|
- Tmux
|
||||||
* Unzip
|
- Unzip
|
||||||
|
|
||||||
### Make sure **npm** is up-to-date.
|
### Make sure **npm** is up-to-date.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ npm update
|
$ npm update
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup a Webserver to serve **Spee.ch** from Port **3000**.
|
### Setup a Webserver to serve **Spee.ch** from Port **3000**.
|
||||||
* If you are using a server provided by **lbry**, we will have **caddy** installed already.
|
|
||||||
* If you are using your own server, make sure to have a web server installed and set up to serve from port **3000**.
|
- If you are using a server provided by **lbry**, we will have **caddy** installed already.
|
||||||
* Nginx instructions (recommended).
|
- If you are using your own server, make sure to have a web server installed and set up to serve from port **3000**.
|
||||||
* Insert directions for certbot before installing.
|
- Nginx instructions (recommended).
|
||||||
* Install [Nginx](http://nginx.org/en/docs/install.html).
|
|
||||||
* Create a config file called `spee.ch` in */etc/nginx/sites-available*
|
- Insert directions for certbot before installing.
|
||||||
* see example: [config file](https://github.com/lbryio/spee.ch/blob/master/nginx_example_config).
|
- Install [Nginx](http://nginx.org/en/docs/install.html).
|
||||||
* Rename all mentions of *sub.domain.com* with your subdomain name.
|
- Create a config file called `spee.ch` in _/etc/nginx/sites-available_
|
||||||
* Run this command to link the sites-available.
|
- see example: [config file](https://github.com/lbryio/spee.ch/blob/master/nginx_example_config).
|
||||||
|
- Rename all mentions of _sub.domain.com_ with your subdomain name.
|
||||||
|
- Run this command to link the sites-available.
|
||||||
|
|
||||||
`$ ln -s /etc/nginx/sites-available/speech /etc/nginx/sites-enabled/speech`
|
`$ ln -s /etc/nginx/sites-available/speech /etc/nginx/sites-enabled/speech`
|
||||||
|
|
||||||
* Restart Nginx.
|
- Restart Nginx.
|
||||||
|
|
||||||
`$ sudo service nginx restart`
|
`$ sudo service nginx restart`
|
||||||
|
|
||||||
* Try visiting your website.
|
- Try visiting your website.
|
||||||
* If Nginx is working, you should get a **502** error because there is nothing running on **3000** yet.
|
- If Nginx is working, you should get a **502** error because there is nothing running on **3000** yet.
|
||||||
* If you get the default Nginx greeting, you have not properly configured it to serve from port **3000**.
|
- If you get the default Nginx greeting, you have not properly configured it to serve from port **3000**.
|
||||||
* You can find logs in */var/log/nginx/* too.
|
- You can find logs in _/var/log/nginx/_ too.
|
||||||
* Caddy tutorial: [https://caddyserver.com/tutorial](https://caddyserver.com/tutorial)
|
- Caddy tutorial: [https://caddyserver.com/tutorial](https://caddyserver.com/tutorial)
|
||||||
|
|
||||||
### MySql
|
### MySql
|
||||||
|
|
||||||
* Install MySql
|
- Install MySql
|
||||||
* [Instructions](https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en)
|
- [Instructions](https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en)
|
||||||
* Create user **root**.
|
- Create user **root**. \* Note: We are going to access **mysql** as **root** for this setup, but you may want to create a separate user in the future.
|
||||||
* Note: We are going to access **mysql** as **root** for this setup, but you may want to create a separate user in the future.
|
- Keep your password somewhere handy!
|
||||||
* Keep your password somewhere handy!
|
- Create a database called **lbry** and make sure you can use it.
|
||||||
* Create a database called **lbry** and make sure you can use it.
|
|
||||||
|
|
||||||
`CREATE DATABASE lbry;`
|
`CREATE DATABASE lbry;`
|
||||||
|
|
||||||
|
@ -53,22 +57,26 @@ $ npm update
|
||||||
|
|
||||||
`$ exit; (or press ‘ctl + d’)`
|
`$ exit; (or press ‘ctl + d’)`
|
||||||
|
|
||||||
* Try logging into mysql.
|
- Try logging into mysql.
|
||||||
|
|
||||||
`$ mysql -u username -p`
|
`$ mysql -u username -p`
|
||||||
|
|
||||||
* If you are using a **LBRY** server, your **password** is the one provided for **ssh**.
|
- If you are using a **LBRY** server, your **password** is the one provided for **ssh**.
|
||||||
* Note: If it fails, try using `sudo`.
|
- Note: If it fails, try using `sudo`.
|
||||||
|
|
||||||
##2. Install & Run the LBRY Daemon
|
##2. Install & Run the LBRY Daemon
|
||||||
|
|
||||||
### Install **lbrynet**
|
### Install **lbrynet**
|
||||||
|
|
||||||
_note: if you have a server from LBRY, lbrynet is already installed, you can skip to 2.4._
|
_note: if you have a server from LBRY, lbrynet is already installed, you can skip to 2.4._
|
||||||
|
|
||||||
```
|
```
|
||||||
$ wget --quiet -O ~/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip
|
$ wget --quiet -O ~/latest_daemon.zip https://lbry.com/get/lbrynet.linux.zip
|
||||||
$ unzip -o -u "~/latest_daemon.zip"
|
$ unzip -o -u "~/latest_daemon.zip"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Start lbrynet
|
### Start lbrynet
|
||||||
|
|
||||||
```
|
```
|
||||||
$ tmux
|
$ tmux
|
||||||
$ ./lbrynet-daemon
|
$ ./lbrynet-daemon
|
||||||
|
@ -127,6 +135,7 @@ $ npm run configure
|
||||||
```
|
```
|
||||||
|
|
||||||
Check your site configs
|
Check your site configs
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cd /site/config/
|
$ cd /site/config/
|
||||||
$ nano siteConfig.json
|
$ nano siteConfig.json
|
||||||
|
@ -135,6 +144,7 @@ $ nano siteConfig.json
|
||||||
### Build & run
|
### Build & run
|
||||||
|
|
||||||
Run the below command to transpile, build, and start your server.
|
Run the below command to transpile, build, and start your server.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ npm run start
|
$ npm run start
|
||||||
```
|
```
|
||||||
|
@ -145,17 +155,18 @@ Spee.ch should now be running !
|
||||||
|
|
||||||
Visit your site in the browser. Try publishing an image!
|
Visit your site in the browser. Try publishing an image!
|
||||||
|
|
||||||
|
|
||||||
## 4. Bonus:
|
## 4. Bonus:
|
||||||
|
|
||||||
### Install PM2 and run your server with PM2
|
### Install PM2 and run your server with PM2
|
||||||
|
|
||||||
Install PM2
|
Install PM2
|
||||||
|
|
||||||
```
|
```
|
||||||
$ sudo npm i -g pm2
|
$ sudo npm i -g pm2
|
||||||
```
|
```
|
||||||
|
|
||||||
From inside your project’s folder, start your server with PM2.
|
From inside your project’s folder, start your server with PM2.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ pm2 start server.js
|
$ pm2 start server.js
|
||||||
```
|
```
|
||||||
|
|
371
package-lock.json
generated
371
package-lock.json
generated
|
@ -1522,20 +1522,11 @@
|
||||||
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
|
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
|
||||||
"dev": true
|
"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": {
|
"amdefine": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
|
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-align": {
|
"ansi-align": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -1660,6 +1651,16 @@
|
||||||
"es-abstract": "^1.7.0"
|
"es-abstract": "^1.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"array-parallel": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
|
||||||
|
"integrity": "sha1-j3hTCJJu1apHjEfmTRszS2wMlH0="
|
||||||
|
},
|
||||||
|
"array-series": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
|
||||||
|
"integrity": "sha1-3103v8XC7wdV4qpPkv6ufUtaly8="
|
||||||
|
},
|
||||||
"array-union": {
|
"array-union": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||||
|
@ -1728,7 +1729,7 @@
|
||||||
},
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"version": "0.10.3",
|
"version": "0.10.3",
|
||||||
"resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
|
||||||
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
|
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -1754,11 +1755,6 @@
|
||||||
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
|
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"async": {
|
|
||||||
"version": "1.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
|
||||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
|
||||||
},
|
|
||||||
"async-each": {
|
"async-each": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
|
||||||
|
@ -1807,12 +1803,19 @@
|
||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.1",
|
||||||
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
|
||||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
"integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.3.0",
|
"follow-redirects": "1.5.10",
|
||||||
"is-buffer": "^1.1.5"
|
"is-buffer": "^2.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"babel-eslint": {
|
"babel-eslint": {
|
||||||
|
@ -2613,6 +2616,7 @@
|
||||||
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "^2.3.5",
|
"readable-stream": "^2.3.5",
|
||||||
"safe-buffer": "^5.1.1"
|
"safe-buffer": "^5.1.1"
|
||||||
|
@ -3005,12 +3009,6 @@
|
||||||
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
|
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
|
||||||
"dev": true
|
"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": {
|
"camelcase-keys": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||||
|
@ -3078,16 +3076,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
"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": {
|
"chai": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
|
||||||
|
@ -3331,25 +3319,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
|
||||||
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
|
"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": {
|
"clone-deep": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
|
||||||
|
@ -3642,6 +3611,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
},
|
},
|
||||||
|
"cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"requires": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"cosmiconfig": {
|
"cosmiconfig": {
|
||||||
"version": "5.0.7",
|
"version": "5.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz",
|
||||||
|
@ -3977,7 +3955,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
|
@ -3989,6 +3967,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
|
||||||
"integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
|
"integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"file-type": "^5.2.0",
|
"file-type": "^5.2.0",
|
||||||
"is-stream": "^1.1.0",
|
"is-stream": "^1.1.0",
|
||||||
|
@ -4023,6 +4002,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
|
||||||
"integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
|
"integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"decompress-tar": "^4.1.1",
|
"decompress-tar": "^4.1.1",
|
||||||
"file-type": "^5.2.0",
|
"file-type": "^5.2.0",
|
||||||
|
@ -4044,14 +4024,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"file-type": {
|
"file-type": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
|
||||||
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
|
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"get-stream": {
|
"get-stream": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
|
||||||
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
|
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
@ -4062,7 +4042,7 @@
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
|
@ -5178,7 +5158,7 @@
|
||||||
},
|
},
|
||||||
"external-editor": {
|
"external-editor": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
|
||||||
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
|
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"chardet": "^0.4.0",
|
"chardet": "^0.4.0",
|
||||||
|
@ -5413,7 +5393,8 @@
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
|
||||||
"integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
|
"integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"fill-range": {
|
"fill-range": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
@ -5530,11 +5511,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.5.7",
|
"version": "1.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||||
"integrity": "sha512-NONJVIFiX7Z8k2WxfqBjtwqMifx7X42ORLFrOZ2LTKGj71G3C0kfdyTqGqr8fx5zSX6Foo/D95dgGWbPUiwnew==",
|
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "^3.1.0"
|
"debug": "=3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"for-in": {
|
"for-in": {
|
||||||
|
@ -5611,7 +5592,8 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"fs-extra": {
|
"fs-extra": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
|
@ -5644,8 +5626,7 @@
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
|
@ -5667,7 +5648,8 @@
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
|
@ -5688,12 +5670,14 @@
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
|
@ -5708,17 +5692,20 @@
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -5835,7 +5822,8 @@
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
|
@ -5847,6 +5835,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
@ -5861,6 +5850,7 @@
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
|
@ -5868,12 +5858,14 @@
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.1",
|
"safe-buffer": "^5.1.1",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
|
@ -5892,6 +5884,7 @@
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
|
@ -5972,7 +5965,8 @@
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
|
@ -5984,6 +5978,7 @@
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
|
@ -6069,7 +6064,8 @@
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
|
@ -6105,6 +6101,7 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
|
@ -6124,6 +6121,7 @@
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
@ -6167,20 +6165,21 @@
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fstream": {
|
"fstream": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
|
||||||
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
|
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
"inherits": "~2.0.0",
|
"inherits": "~2.0.0",
|
||||||
|
@ -6254,7 +6253,7 @@
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -6441,7 +6440,7 @@
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
|
@ -6474,6 +6473,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"gm": {
|
||||||
|
"version": "1.23.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz",
|
||||||
|
"integrity": "sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=",
|
||||||
|
"requires": {
|
||||||
|
"array-parallel": "~0.1.3",
|
||||||
|
"array-series": "~0.1.5",
|
||||||
|
"cross-spawn": "^4.0.0",
|
||||||
|
"debug": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
|
||||||
|
"integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "^4.0.1",
|
||||||
|
"which": "^1.2.9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"got": {
|
"got": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.1",
|
||||||
"resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
"resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
||||||
|
@ -6512,14 +6533,26 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"handlebars": {
|
"handlebars": {
|
||||||
"version": "4.0.11",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
|
||||||
"integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
|
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "^1.4.0",
|
"neo-async": "^2.6.0",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"source-map": "^0.4.4",
|
"source-map": "^0.6.1",
|
||||||
"uglify-js": "^2.6"
|
"uglify-js": "^3.1.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"neo-async": {
|
||||||
|
"version": "2.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
|
||||||
|
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
|
||||||
|
},
|
||||||
|
"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": {
|
"har-schema": {
|
||||||
|
@ -6789,7 +6822,7 @@
|
||||||
},
|
},
|
||||||
"http-errors": {
|
"http-errors": {
|
||||||
"version": "1.6.3",
|
"version": "1.6.3",
|
||||||
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||||
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"depd": "~1.1.2",
|
"depd": "~1.1.2",
|
||||||
|
@ -7594,6 +7627,11 @@
|
||||||
"buffer-alloc": "^1.2.0"
|
"buffer-alloc": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"isbot": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isbot/-/isbot-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-z0idtpC0uKKKTBhd1g73GREBWhCQdnJq8U5o+8XhgPvuPiRb/vkpNreLvtoneaZX9FNxDFOU0ohEj9hTWm/tPw=="
|
||||||
|
},
|
||||||
"isemail": {
|
"isemail": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
|
||||||
|
@ -7685,9 +7723,9 @@
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.12.0",
|
"version": "3.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
"esprima": "^4.0.0"
|
"esprima": "^4.0.0"
|
||||||
|
@ -7775,6 +7813,7 @@
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-buffer": "^1.1.5"
|
"is-buffer": "^1.1.5"
|
||||||
}
|
}
|
||||||
|
@ -7788,12 +7827,6 @@
|
||||||
"package-json": "^4.0.0"
|
"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": {
|
"lcid": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
||||||
|
@ -8091,9 +8124,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.13",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
"integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA=="
|
||||||
},
|
},
|
||||||
"lodash.assign": {
|
"lodash.assign": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
|
@ -8125,9 +8158,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash.mergewith": {
|
"lodash.mergewith": {
|
||||||
"version": "4.6.1",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
|
||||||
"integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==",
|
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash.tail": {
|
"lodash.tail": {
|
||||||
|
@ -8173,11 +8206,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
"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": {
|
"loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
@ -8375,7 +8403,7 @@
|
||||||
},
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -8414,7 +8442,7 @@
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -8586,9 +8614,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mixin-deep": {
|
"mixin-deep": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
|
||||||
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
|
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"for-in": "^1.0.2",
|
"for-in": "^1.0.2",
|
||||||
|
@ -8975,7 +9003,7 @@
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
|
@ -9068,7 +9096,7 @@
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -9105,7 +9133,7 @@
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -9336,7 +9364,7 @@
|
||||||
},
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "5.5.2",
|
"version": "5.5.2",
|
||||||
"resolved": false,
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"co": "^4.6.0",
|
"co": "^4.6.0",
|
||||||
|
@ -9649,7 +9677,7 @@
|
||||||
},
|
},
|
||||||
"co": {
|
"co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": false,
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
||||||
},
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
|
@ -9986,7 +10014,7 @@
|
||||||
},
|
},
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": false,
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
|
@ -10086,17 +10114,6 @@
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
},
|
},
|
||||||
"fstream": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": false,
|
|
||||||
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "^4.1.2",
|
|
||||||
"inherits": "~2.0.0",
|
|
||||||
"mkdirp": ">=0.5 0",
|
|
||||||
"rimraf": "2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gauge": {
|
"gauge": {
|
||||||
"version": "2.7.4",
|
"version": "2.7.4",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
|
@ -10498,7 +10515,7 @@
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": false,
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||||
},
|
},
|
||||||
"json-stringify-safe": {
|
"json-stringify-safe": {
|
||||||
|
@ -13299,6 +13316,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-image": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-image/-/react-image-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-yWf+UAtkavJFSG1Qa4p111KncN7/a8dAOUUi5On3jjwZU1tzMXFpBnOFp04vYQr8fJmS/7ePp1OsK440WZ4fLA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"prop-types": "15.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-input-autosize": {
|
"react-input-autosize": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz",
|
||||||
|
@ -13838,20 +13864,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": {
|
"rimraf": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.0.5"
|
"glob": "^7.0.5"
|
||||||
},
|
},
|
||||||
|
@ -13860,7 +13876,6 @@
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
|
@ -14018,7 +14033,7 @@
|
||||||
},
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -14031,7 +14046,7 @@
|
||||||
},
|
},
|
||||||
"os-locale": {
|
"os-locale": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
||||||
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -14060,7 +14075,7 @@
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -14098,7 +14113,7 @@
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -14234,7 +14249,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
|
||||||
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
|
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
@ -14714,6 +14729,7 @@
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"amdefine": ">=0.0.4"
|
"amdefine": ">=0.0.4"
|
||||||
}
|
}
|
||||||
|
@ -15153,6 +15169,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
|
||||||
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
|
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"bl": "^1.0.0",
|
"bl": "^1.0.0",
|
||||||
"buffer-alloc": "^1.2.0",
|
"buffer-alloc": "^1.2.0",
|
||||||
|
@ -15415,7 +15432,8 @@
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
|
||||||
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
|
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"to-fast-properties": {
|
"to-fast-properties": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -15619,30 +15637,23 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "2.8.29",
|
"version": "3.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
|
||||||
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
|
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"source-map": "~0.5.1",
|
"commander": "~2.17.1",
|
||||||
"uglify-to-browserify": "~1.0.0",
|
"source-map": "~0.6.1"
|
||||||
"yargs": "~3.10.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"optional": true
|
"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": {
|
"uid-safe": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
|
@ -16597,7 +16608,7 @@
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -16684,12 +16695,6 @@
|
||||||
"string-width": "^2.1.1"
|
"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": {
|
"winston": {
|
||||||
"version": "2.4.4",
|
"version": "2.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz",
|
||||||
|
@ -16705,7 +16710,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": {
|
"async": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
||||||
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
|
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16849,18 +16854,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
"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": {
|
"yargs-parser": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
|
||||||
|
|
|
@ -36,21 +36,24 @@
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.8",
|
"@fortawesome/fontawesome-svg-core": "^1.2.8",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.5.0",
|
"@fortawesome/free-solid-svg-icons": "^5.5.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.3",
|
"@fortawesome/react-fontawesome": "^0.1.3",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.1",
|
||||||
"bcrypt": "^3.0.3",
|
"bcrypt": "^3.0.3",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
"connect-multiparty": "^2.2.0",
|
"connect-multiparty": "^2.2.0",
|
||||||
"cookie-session": "^2.0.0-beta.3",
|
"cookie-session": "^2.0.0-beta.3",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"express-handlebars": "^3.0.0",
|
"express-handlebars": "^3.0.0",
|
||||||
"express-http-context": "^1.2.0",
|
"express-http-context": "^1.2.0",
|
||||||
"generate-password": "^1.4.1",
|
"generate-password": "^1.4.1",
|
||||||
"get-video-dimensions": "^1.0.0",
|
"get-video-dimensions": "^1.0.0",
|
||||||
|
"gm": "^1.23.1",
|
||||||
"helmet": "^3.15.0",
|
"helmet": "^3.15.0",
|
||||||
"image-size": "^0.6.3",
|
"image-size": "^0.6.3",
|
||||||
"inquirer": "^5.2.0",
|
"inquirer": "^5.2.0",
|
||||||
"ip": "^1.1.5",
|
"ip": "^1.1.5",
|
||||||
"lodash": "^4.17.11",
|
"isbot": "^2.2.1",
|
||||||
|
"lodash": "^4.17.13",
|
||||||
"make-dir": "^1.3.0",
|
"make-dir": "^1.3.0",
|
||||||
"mime-types": "^2.1.21",
|
"mime-types": "^2.1.21",
|
||||||
"module-alias": "^2.1.0",
|
"module-alias": "^2.1.0",
|
||||||
|
@ -65,6 +68,7 @@
|
||||||
"react-feather": "^1.1.4",
|
"react-feather": "^1.1.4",
|
||||||
"react-ga": "^2.5.3",
|
"react-ga": "^2.5.3",
|
||||||
"react-helmet": "^5.2.0",
|
"react-helmet": "^5.2.0",
|
||||||
|
"react-image": "^2.0.0",
|
||||||
"react-markdown": "^4.0.6",
|
"react-markdown": "^4.0.6",
|
||||||
"react-redux": "^5.1.1",
|
"react-redux": "^5.1.1",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
|
|
BIN
public/assets/img/default_thumb.jpg
Normal file
BIN
public/assets/img/default_thumb.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
|
@ -6,7 +6,7 @@ const {
|
||||||
|
|
||||||
const getterMethods = {
|
const getterMethods = {
|
||||||
generated_extension() {
|
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)) {
|
if (customFileExtensions.hasOwnProperty(this.content_type)) {
|
||||||
return customFileExtensions[this.content_type];
|
return customFileExtensions[this.content_type];
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,6 +136,14 @@ export default (sequelize, { BOOLEAN, DATE, DECIMAL, ENUM, INTEGER, STRING, TEXT
|
||||||
type: STRING,
|
type: STRING,
|
||||||
set() {},
|
set() {},
|
||||||
},
|
},
|
||||||
|
license: {
|
||||||
|
type: STRING,
|
||||||
|
set() {},
|
||||||
|
},
|
||||||
|
license_url: {
|
||||||
|
type: STRING,
|
||||||
|
set() {},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
freezeTableName: true,
|
freezeTableName: true,
|
||||||
|
|
|
@ -82,6 +82,7 @@ export default (db, table, sequelize) => ({
|
||||||
};
|
};
|
||||||
const selectWhere = {
|
const selectWhere = {
|
||||||
...whereClause,
|
...whereClause,
|
||||||
|
claim_type: 1,
|
||||||
publisher_id: channelClaimId,
|
publisher_id: channelClaimId,
|
||||||
};
|
};
|
||||||
return await table
|
return await table
|
||||||
|
@ -103,6 +104,7 @@ export default (db, table, sequelize) => ({
|
||||||
.findAll({
|
.findAll({
|
||||||
where: {
|
where: {
|
||||||
name: claimName,
|
name: claimName,
|
||||||
|
claim_type: 1,
|
||||||
publisher_id: channelClaimId,
|
publisher_id: channelClaimId,
|
||||||
bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] },
|
bid_state: { [sequelize.Op.or]: ['Controlling', 'Active', 'Accepted'] },
|
||||||
},
|
},
|
||||||
|
@ -201,6 +203,10 @@ export default (db, table, sequelize) => ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return claimArray[0];
|
return claimArray[0];
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.verbose(`resolveClaim failed: ${error}`)
|
||||||
|
reject(error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -210,6 +216,7 @@ export default (db, table, sequelize) => ({
|
||||||
.findAll({
|
.findAll({
|
||||||
where: {
|
where: {
|
||||||
name: claimName,
|
name: claimName,
|
||||||
|
claim_type: 1,
|
||||||
publisher_id: channelId,
|
publisher_id: channelId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
const chainquery = require('chainquery').default;
|
const chainquery = require('chainquery').default;
|
||||||
|
const logger = require('winston');
|
||||||
const getClaimData = require('server/utils/getClaimData');
|
const getClaimData = require('server/utils/getClaimData');
|
||||||
const { returnPaginatedChannelClaims } = require('./channelPagination.js');
|
const { returnPaginatedChannelClaims } = require('./channelPagination.js');
|
||||||
|
|
||||||
const getChannelClaims = async (channelName, channelLongId, page) => {
|
const getChannelClaims = async (channelName, channelLongId, page) => {
|
||||||
|
logger.debug(`getChannelClaims: ${channelName}, ${channelLongId}, ${page}`);
|
||||||
let channelShortId = await chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
let channelShortId = await chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
||||||
channelLongId,
|
channelLongId,
|
||||||
channelName
|
channelName
|
||||||
|
|
|
@ -9,28 +9,28 @@ const authenticateUser = require('../publish/authentication.js');
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const claimAbandon = async (req, res) => {
|
const claimAbandon = async (req, res) => {
|
||||||
const {claimId} = req.body;
|
const { outpoint } = req.body;
|
||||||
const {user} = req;
|
const { user } = req;
|
||||||
try {
|
try {
|
||||||
const [channel, claim] = await Promise.all([
|
const [channel, claim] = await Promise.all([
|
||||||
authenticateUser(user.channelName, null, null, user),
|
authenticateUser(user.channelName, null, null, user),
|
||||||
db.Claim.findOne({where: {claimId}}),
|
db.Claim.findOne({ where: { outpoint } }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!claim) throw new Error('That channel does not exist');
|
if (!claim) throw new Error('That channel does not exist');
|
||||||
if (!channel.channelName) throw new Error('You don\'t own this channel');
|
if (!channel.channelName) throw new Error("You don't own this channel");
|
||||||
|
|
||||||
await abandonClaim({claimId});
|
await abandonClaim({ outpoint });
|
||||||
const file = await db.File.findOne({where: {claimId}});
|
const file = await db.File.findOne({ where: { outpoint } });
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
deleteFile(file.filePath),
|
deleteFile(file.filePath),
|
||||||
db.File.destroy({where: {claimId}}),
|
db.File.destroy({ where: { outpoint } }),
|
||||||
db.Claim.destroy({where: {claimId}}),
|
db.Claim.destroy({ where: { outpoint } }),
|
||||||
]);
|
]);
|
||||||
logger.debug(`Claim abandoned: ${claimId}`);
|
logger.debug(`Claim abandoned: ${outpoint}`);
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: `Claim with id ${claimId} abandonded`,
|
message: `Claim with outpoint ${outpoint} abandonded`,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('abandon claim error:', error);
|
logger.error('abandon claim error:', error);
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
const { getClaim } = require('../../../../lbrynet');
|
const { getClaim, resolveUri } = require('server/lbrynet');
|
||||||
const { createFileRecordDataAfterGet } = require('../../../../models/utils/createFileRecordData.js');
|
const { createFileRecordDataAfterGet } = require('server/models/utils/createFileRecordData.js');
|
||||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const getClaimData = require('server/utils/getClaimData');
|
const getClaimData = require('server/utils/getClaimData');
|
||||||
const chainquery = require('chainquery').default;
|
const chainquery = require('chainquery').default;
|
||||||
const db = require('../../../../models');
|
const db = require('server/models');
|
||||||
const waitOn = require('wait-on');
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
const awaitFileSize = require('server/utils/awaitFileSize');
|
||||||
|
const isBot = require('isbot');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -13,14 +14,14 @@ const logger = require('winston');
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const claimGet = async ({ ip, originalUrl, params }, res) => {
|
const claimGet = async ({ ip, originalUrl, params, headers }, res) => {
|
||||||
const name = params.name;
|
const name = params.name;
|
||||||
const claimId = params.claimId;
|
const claimId = params.claimId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let claimInfo = await chainquery.claim.queries.resolveClaim(name, claimId).catch(() => {});
|
let claimInfo = await chainquery.claim.queries.resolveClaim(name, claimId).catch(() => {});
|
||||||
if (claimInfo) {
|
if (claimInfo) {
|
||||||
logger.info('claim/get: claim resolved in chainquery');
|
logger.debug(`claim/get: claim resolved in chainquery`);
|
||||||
}
|
}
|
||||||
if (!claimInfo) {
|
if (!claimInfo) {
|
||||||
claimInfo = await db.Claim.resolveClaim(name, claimId);
|
claimInfo = await db.Claim.resolveClaim(name, claimId);
|
||||||
|
@ -28,6 +29,16 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
|
||||||
if (!claimInfo) {
|
if (!claimInfo) {
|
||||||
throw new Error('claim/get: resolveClaim: No matching uri found in Claim table');
|
throw new Error('claim/get: resolveClaim: No matching uri found in Claim table');
|
||||||
}
|
}
|
||||||
|
if (headers && headers['user-agent'] && isBot(headers['user-agent'])) {
|
||||||
|
logger.info(`Bot GetClaim: claimId: ${claimId}`);
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
message: 'bot',
|
||||||
|
completed: false,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
logger.info(`GetClaim: ${claimId} UA: ${headers['user-agent']}`);
|
||||||
let lbrynetResult = await getClaim(`${name}#${claimId}`);
|
let lbrynetResult = await getClaim(`${name}#${claimId}`);
|
||||||
if (!lbrynetResult) {
|
if (!lbrynetResult) {
|
||||||
throw new Error(`claim/get: getClaim Unable to Get ${name}#${claimId}`);
|
throw new Error(`claim/get: getClaim Unable to Get ${name}#${claimId}`);
|
||||||
|
@ -36,11 +47,11 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
|
||||||
if (!claimData) {
|
if (!claimData) {
|
||||||
throw new Error('claim/get: getClaimData failed to get file blobs');
|
throw new Error('claim/get: getClaimData failed to get file blobs');
|
||||||
}
|
}
|
||||||
await waitOn({
|
const fileReady = await awaitFileSize(lbrynetResult.outpoint, 10000000, 250, 10000);
|
||||||
resources: [ lbrynetResult.download_path ],
|
|
||||||
timeout : 10000, // 10 seconds
|
if (fileReady !== 'ready') {
|
||||||
window : 500,
|
throw new Error('claim/get: failed to get file after 10 seconds');
|
||||||
});
|
}
|
||||||
const fileData = await createFileRecordDataAfterGet(claimData, lbrynetResult);
|
const fileData = await createFileRecordDataAfterGet(claimData, lbrynetResult);
|
||||||
if (!fileData) {
|
if (!fileData) {
|
||||||
throw new Error('claim/get: createFileRecordDataAfterGet failed to create file in time');
|
throw new Error('claim/get: createFileRecordDataAfterGet failed to create file in time');
|
||||||
|
|
|
@ -36,7 +36,7 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
||||||
return db.Blocked.isNotBlocked(outpoint);
|
return db.Blocked.isNotBlocked(outpoint);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.status(200).json({success: true, data: claimId});
|
res.status(200).json({ success: true, data: claimId });
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error === NO_CLAIM) {
|
if (error === NO_CLAIM) {
|
||||||
|
@ -54,7 +54,8 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
||||||
if (error === BLOCKED_CLAIM) {
|
if (error === BLOCKED_CLAIM) {
|
||||||
return res.status(410).json({
|
return res.status(410).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
message:
|
||||||
|
'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.com/faq/dmca',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleErrorResponse(originalUrl, ip, error, res);
|
handleErrorResponse(originalUrl, ip, error, res);
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { details, publishing } = require('@config/siteConfig');
|
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
|
// provide defaults for title
|
||||||
if (title === null || title.trim() === '') {
|
if (title === null || title.trim() === '') {
|
||||||
title = name;
|
title = name;
|
||||||
|
@ -13,29 +24,35 @@ const createPublishParams = (filePath, name, title, description, license, nsfw,
|
||||||
if (license === null || license.trim() === '') {
|
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
|
// create the basic publish params
|
||||||
const publishParams = {
|
const publishParams = {
|
||||||
name,
|
name,
|
||||||
file_path: filePath,
|
file_path: filePath,
|
||||||
bid : publishing.fileClaimBidAmount,
|
bid: publishing.fileClaimBidAmount,
|
||||||
metadata : {
|
|
||||||
description,
|
description,
|
||||||
title,
|
title,
|
||||||
author : details.title,
|
author: details.title,
|
||||||
language: 'en',
|
languages: ['en'],
|
||||||
license,
|
license,
|
||||||
nsfw,
|
license_url: licenseUrl,
|
||||||
},
|
tags: [],
|
||||||
claim_address: publishing.primaryClaimAddress,
|
claim_address: publishing.primaryClaimAddress,
|
||||||
};
|
};
|
||||||
// add thumbnail to channel if video
|
// add thumbnail to channel if video
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
publishParams['metadata']['thumbnail'] = thumbnail;
|
publishParams['thumbnail_url'] = thumbnail;
|
||||||
|
}
|
||||||
|
if (nsfw) {
|
||||||
|
publishParams.tags = ['mature'];
|
||||||
}
|
}
|
||||||
// add channel details if publishing to a channel
|
// add channel details if publishing to a channel
|
||||||
if (channelName && channelClaimId) {
|
if (channelName && channelClaimId) {
|
||||||
publishParams['channel_name'] = channelName;
|
|
||||||
publishParams['channel_id'] = channelClaimId;
|
publishParams['channel_id'] = channelClaimId;
|
||||||
|
publishParams['channel_name'] = channelName;
|
||||||
}
|
}
|
||||||
// log params
|
// log params
|
||||||
logger.debug('publish params:', publishParams);
|
logger.debug('publish params:', publishParams);
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { details, publishing } = require('@config/siteConfig');
|
const { details, publishing } = require('@config/siteConfig');
|
||||||
|
|
||||||
const createThumbnailPublishParams = (thumbnailFilePath, claimName, license, nsfw) => {
|
const createThumbnailPublishParams = (thumbnailFilePath, claimName, license, licenseUrl, nsfw) => {
|
||||||
if (!thumbnailFilePath) {
|
if (!thumbnailFilePath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug(`Creating Thumbnail Publish Parameters`);
|
logger.debug(`Creating Thumbnail Publish Parameters`);
|
||||||
// create the publish params
|
// create the publish params
|
||||||
|
|
||||||
|
if (license === null || license.trim() === '') {
|
||||||
|
license = ''; // default to empty string
|
||||||
|
}
|
||||||
|
// provide default for licenseUrl
|
||||||
|
if (licenseUrl === null || licenseUrl.trim() === '') {
|
||||||
|
licenseUrl = ''; // default to empty string
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name : `${claimName}-thumb`,
|
name: `${claimName}-thumb`,
|
||||||
file_path: thumbnailFilePath,
|
file_path: thumbnailFilePath,
|
||||||
bid : publishing.fileClaimBidAmount,
|
bid: publishing.fileClaimBidAmount,
|
||||||
metadata : {
|
title: `${claimName} thumbnail`,
|
||||||
title : `${claimName} thumbnail`,
|
|
||||||
description: `a thumbnail for ${claimName}`,
|
description: `a thumbnail for ${claimName}`,
|
||||||
author : details.title,
|
author: details.title,
|
||||||
language : 'en',
|
languages: ['en'],
|
||||||
license,
|
license,
|
||||||
nsfw,
|
license_url: licenseUrl,
|
||||||
},
|
|
||||||
claim_address: publishing.primaryClaimAddress,
|
claim_address: publishing.primaryClaimAddress,
|
||||||
channel_name : publishing.thumbnailChannel,
|
channel_name: publishing.thumbnailChannel,
|
||||||
channel_id : publishing.thumbnailChannelId,
|
channel_id: publishing.thumbnailChannelId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
const logger = require('winston');
|
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 isApprovedChannel = require('@globalutils/isApprovedChannel');
|
||||||
const { publishing: { publishOnlyApproved, approvedChannels } } = require('@config/siteConfig');
|
const {
|
||||||
|
publishing: { publishOnlyApproved, approvedChannels },
|
||||||
|
} = require('@config/siteConfig');
|
||||||
|
|
||||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
|
|
||||||
|
@ -55,6 +60,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
fileType,
|
fileType,
|
||||||
gaStartTime,
|
gaStartTime,
|
||||||
license,
|
license,
|
||||||
|
licenseUrl,
|
||||||
name,
|
name,
|
||||||
nsfw,
|
nsfw,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
|
@ -69,18 +75,34 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
// validate the body and files of the request
|
// validate the body and files of the request
|
||||||
try {
|
try {
|
||||||
// validateApiPublishRequest(body, files);
|
// validateApiPublishRequest(body, files);
|
||||||
({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
|
({
|
||||||
({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
|
name,
|
||||||
({channelName, channelId, channelPassword} = body);
|
nsfw,
|
||||||
|
license,
|
||||||
|
licenseUrl,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
} = parsePublishApiRequestBody(body));
|
||||||
|
({
|
||||||
|
fileName,
|
||||||
|
filePath,
|
||||||
|
fileExtension,
|
||||||
|
fileType,
|
||||||
|
thumbnailFileName,
|
||||||
|
thumbnailFilePath,
|
||||||
|
thumbnailFileType,
|
||||||
|
} = parsePublishApiRequestFiles(files));
|
||||||
|
({ channelName, channelId, channelPassword } = body);
|
||||||
} catch (error) {
|
} 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
|
// check channel authorization
|
||||||
authenticateUser(channelName, channelId, channelPassword, user)
|
authenticateUser(channelName, channelId, channelPassword, user)
|
||||||
.then(({ channelName, channelClaimId }) => {
|
.then(({ channelName, channelClaimId }) => {
|
||||||
if (publishOnlyApproved && !isApprovedChannel({ longId: channelClaimId }, approvedChannels)) {
|
if (publishOnlyApproved && !isApprovedChannel({ longId: channelClaimId }, approvedChannels)) {
|
||||||
const error = {
|
const error = {
|
||||||
name : UNAPPROVED_CHANNEL,
|
name: UNAPPROVED_CHANNEL,
|
||||||
message: 'This spee.ch instance only allows publishing to approved channels',
|
message: 'This spee.ch instance only allows publishing to approved channels',
|
||||||
};
|
};
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -88,14 +110,25 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
checkClaimAvailability(name),
|
checkClaimAvailability(name),
|
||||||
createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId),
|
createPublishParams(
|
||||||
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
|
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) {
|
if (!claimAvailable) {
|
||||||
const error = {
|
const error = {
|
||||||
name : CLAIM_TAKEN,
|
name: CLAIM_TAKEN,
|
||||||
message: 'That claim name is already taken',
|
message: 'That claim name is already taken',
|
||||||
};
|
};
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -108,14 +141,20 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
return publish(publishParams, fileName, fileType, filePath);
|
return publish(publishParams, fileName, fileType, filePath);
|
||||||
})
|
})
|
||||||
.then(publishResults => {
|
.then(publishResults => {
|
||||||
logger.info('Publish success >', publishResults);
|
logger.debug('Publish success >', publishResults);
|
||||||
claimData = publishResults;
|
claimData = publishResults;
|
||||||
({claimId} = claimData);
|
({ claimId } = claimData);
|
||||||
|
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimData.certificateId, channelName);
|
logger.debug(`api/claim/publish: claimData.certificateId ${claimData.certificateId}`);
|
||||||
|
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
||||||
|
claimData.certificateId,
|
||||||
|
channelName
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimId, name, claimData).catch(() => {
|
return chainquery.claim.queries
|
||||||
|
.getShortClaimIdFromLongClaimId(claimId, name, claimData)
|
||||||
|
.catch(() => {
|
||||||
return claimId.slice(0, 1);
|
return claimId.slice(0, 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,13 +170,13 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'publish completed successfully',
|
message: 'publish completed successfully',
|
||||||
data : {
|
data: {
|
||||||
name,
|
name,
|
||||||
claimId,
|
claimId,
|
||||||
url : `${host}${canonicalUrl}`, // for backwards compatability with app
|
url: `${host}${canonicalUrl}`, // for backwards compatability with app
|
||||||
showUrl : `${host}${canonicalUrl}`,
|
showUrl: `${host}${canonicalUrl}`,
|
||||||
serveUrl: `${host}${canonicalUrl}${fileExtension}`,
|
serveUrl: `${host}${canonicalUrl}${fileExtension}`,
|
||||||
pushTo : canonicalUrl,
|
pushTo: canonicalUrl,
|
||||||
claimData,
|
claimData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
const parsePublishApiRequestBody = ({name, nsfw, license, title, description, thumbnail}) => {
|
const parsePublishApiRequestBody = ({
|
||||||
|
name,
|
||||||
|
nsfw,
|
||||||
|
license,
|
||||||
|
licenseUrl,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
}) => {
|
||||||
// validate name
|
// validate name
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw new Error('no name field found in request');
|
throw new Error('no name field found in request');
|
||||||
}
|
}
|
||||||
const invalidNameCharacters = /[^A-Za-z0-9,-]/.exec(name);
|
const invalidNameCharacters = /[^A-Za-z0-9,-]/.exec(name);
|
||||||
if (invalidNameCharacters) {
|
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
|
// optional parameters
|
||||||
nsfw = (nsfw === 'true');
|
nsfw = nsfw === 'true';
|
||||||
license = license || null;
|
license = license || null;
|
||||||
|
licenseUrl = licenseUrl || null;
|
||||||
title = title || null;
|
title = title || null;
|
||||||
description = description || null;
|
description = description || null;
|
||||||
thumbnail = thumbnail || null;
|
thumbnail = thumbnail || null;
|
||||||
|
@ -18,6 +29,7 @@ const parsePublishApiRequestBody = ({name, nsfw, license, title, description, th
|
||||||
name,
|
name,
|
||||||
nsfw,
|
nsfw,
|
||||||
license,
|
license,
|
||||||
|
licenseUrl,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../../../../models');
|
const db = require('server/models');
|
||||||
const { publishClaim } = require('../../../../lbrynet');
|
const { publishClaim } = require('server/lbrynet');
|
||||||
const { createFileRecordDataAfterPublish } = require('../../../../models/utils/createFileRecordData.js');
|
const { createFileRecordDataAfterPublish } = require('server/models/utils/createFileRecordData.js');
|
||||||
const { createClaimRecordDataAfterPublish } = require('../../../../models/utils/createClaimRecordData.js');
|
const {
|
||||||
|
createClaimRecordDataAfterPublish,
|
||||||
|
} = require('server/models/utils/createClaimRecordData.js');
|
||||||
const deleteFile = require('./deleteFile.js');
|
const deleteFile = require('./deleteFile.js');
|
||||||
|
|
||||||
const publish = async (publishParams, fileName, fileType) => {
|
const publish = async (publishParams, fileName, fileType) => {
|
||||||
|
@ -10,58 +12,76 @@ const publish = async (publishParams, fileName, fileType) => {
|
||||||
let channel;
|
let channel;
|
||||||
let fileRecord;
|
let fileRecord;
|
||||||
let newFile = Boolean(publishParams.file_path);
|
let newFile = Boolean(publishParams.file_path);
|
||||||
|
let publishResultsOutput;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
publishResults = await publishClaim(publishParams);
|
publishResults = await publishClaim(publishParams);
|
||||||
logger.info(`Successfully published ${publishParams.name} ${fileName}`, publishResults);
|
publishResultsOutput = publishResults && publishResults.outputs && publishResults.outputs[0];
|
||||||
const outpoint = `${publishResults.output.txid}:${publishResults.output.nout}`;
|
|
||||||
// get the channel information
|
|
||||||
if (publishParams.channel_name) {
|
|
||||||
logger.debug(`this claim was published in channel: ${publishParams.channel_name}`);
|
|
||||||
channel = await db.Channel.findOne({
|
|
||||||
where: {
|
|
||||||
channelName: publishParams.channel_name,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
channel = null;
|
|
||||||
}
|
|
||||||
const certificateId = channel ? channel.channelClaimId : null;
|
|
||||||
const channelName = channel ? channel.channelName : null;
|
|
||||||
|
|
||||||
const claimRecord = await createClaimRecordDataAfterPublish(certificateId, channelName, fileName, fileType, publishParams, publishResults);
|
logger.verbose(`Successfully published ${publishParams.name} ${fileName}`, publishResults);
|
||||||
const {claimId} = claimRecord;
|
const outpoint = `${publishResultsOutput.txid}:${publishResultsOutput.nout}`;
|
||||||
const upsertCriteria = {name: publishParams.name, claimId};
|
// get the channel information
|
||||||
|
// if (publishParams.channel_name) {
|
||||||
|
// logger.debug(`this claim was published in channel: ${publishParams.channel_name}`);
|
||||||
|
// channel = await db.Channel.findOne({
|
||||||
|
// where: {
|
||||||
|
// channelName: publishParams.channel_name,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// channel = null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const certificateId = publishResultsOutput.signing_channel
|
||||||
|
? publishResultsOutput.signing_channel.claim_id
|
||||||
|
: null;
|
||||||
|
const channelName = publishResultsOutput.signing_channel
|
||||||
|
? publishResultsOutput.signing_channel.name
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const claimRecord = await createClaimRecordDataAfterPublish(
|
||||||
|
certificateId,
|
||||||
|
channelName,
|
||||||
|
fileName,
|
||||||
|
fileType,
|
||||||
|
publishParams,
|
||||||
|
publishResultsOutput
|
||||||
|
);
|
||||||
|
const { claimId } = claimRecord;
|
||||||
|
const upsertCriteria = { name: publishParams.name, claimId };
|
||||||
if (newFile) {
|
if (newFile) {
|
||||||
// this is the problem
|
// this is the problem
|
||||||
//
|
//
|
||||||
fileRecord = await createFileRecordDataAfterPublish(fileName, fileType, publishParams, publishResults);
|
fileRecord = await createFileRecordDataAfterPublish(
|
||||||
|
fileName,
|
||||||
|
fileType,
|
||||||
|
publishParams,
|
||||||
|
publishResultsOutput
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
fileRecord = await db.File.findOne({where: {claimId}}).then(result => result.dataValues);
|
fileRecord = await db.File.findOne({ where: { claimId } }).then(result => result.dataValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [file, claim] = await Promise.all([
|
const [file, claim] = await Promise.all([
|
||||||
db.upsert(db.File, fileRecord, upsertCriteria, 'File'),
|
db.upsert(db.File, fileRecord, upsertCriteria, 'File'),
|
||||||
db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim'),
|
db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim'),
|
||||||
]);
|
]);
|
||||||
logger.info(`File and Claim records successfully created (${publishParams.name})`);
|
logger.debug(`File and Claim records successfully created (${publishParams.name})`);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([file.setClaim(claim), claim.setFile(file)]);
|
||||||
file.setClaim(claim),
|
logger.debug(`File and Claim records successfully associated (${publishParams.name})`);
|
||||||
claim.setFile(file),
|
|
||||||
]);
|
|
||||||
logger.info(`File and Claim records successfully associated (${publishParams.name})`);
|
|
||||||
|
|
||||||
return Object.assign({}, claimRecord, {outpoint});
|
return Object.assign({}, claimRecord, { outpoint });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// parse daemon response when err is a string
|
// parse daemon response when err is a string
|
||||||
// this needs work
|
// this needs work
|
||||||
logger.info('publish/publish err:', err);
|
logger.error('publish/publish err:', err);
|
||||||
const error = typeof err === 'string' ? JSON.parse(err) : err;
|
const error = typeof err === 'string' ? JSON.parse(err) : err;
|
||||||
if (publishParams.file_path) {
|
if (publishParams.file_path) {
|
||||||
await deleteFile(publishParams.file_path);
|
await deleteFile(publishParams.file_path);
|
||||||
}
|
}
|
||||||
const message = error.error && error.error.message ? error.error.message : 'Unknown publish error';
|
const message =
|
||||||
|
error.error && error.error.message ? error.error.message : 'Unknown publish error';
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
message,
|
message,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('server/models');
|
const db = require('server/models');
|
||||||
const { details, publishing: { disabled, disabledMessage, primaryClaimAddress } } = require('@config/siteConfig');
|
const {
|
||||||
|
details,
|
||||||
|
publishing: { disabled, disabledMessage, primaryClaimAddress },
|
||||||
|
} = require('@config/siteConfig');
|
||||||
const { resolveUri } = require('server/lbrynet');
|
const { resolveUri } = require('server/lbrynet');
|
||||||
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
|
@ -16,10 +19,11 @@ const createCanonicalLink = require('@globalutils/createCanonicalLink');
|
||||||
route to update a claim through the daemon
|
route to update a claim through the daemon
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const updateMetadata = ({nsfw, license, title, description}) => {
|
const updateMetadata = ({ nsfw, license, licenseUrl, title, description }) => {
|
||||||
const update = {};
|
const update = {};
|
||||||
if (nsfw) update['nsfw'] = nsfw;
|
if (nsfw) update['nsfw'] = nsfw;
|
||||||
if (license) update['license'] = license;
|
if (license) update['license'] = license;
|
||||||
|
if (licenseUrl) update['licenseUrl'] = licenseUrl;
|
||||||
if (title) update['title'] = title;
|
if (title) update['title'] = title;
|
||||||
if (description) update['description'] = description;
|
if (description) update['description'] = description;
|
||||||
return update;
|
return update;
|
||||||
|
@ -34,7 +38,7 @@ const rando = () => {
|
||||||
|
|
||||||
const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res) => {
|
const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res) => {
|
||||||
// logging
|
// logging
|
||||||
logger.info('Claim update request:', {
|
logger.debug('Claim update request:', {
|
||||||
ip,
|
ip,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
|
@ -62,6 +66,7 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
thumbnail,
|
thumbnail,
|
||||||
fileExtension,
|
fileExtension,
|
||||||
license,
|
license,
|
||||||
|
licenseUrl,
|
||||||
name,
|
name,
|
||||||
nsfw,
|
nsfw,
|
||||||
thumbnailFileName,
|
thumbnailFileName,
|
||||||
|
@ -76,11 +81,27 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
gaStartTime = Date.now();
|
gaStartTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
|
({
|
||||||
({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files, true));
|
name,
|
||||||
({channelName, channelId, channelPassword} = body);
|
nsfw,
|
||||||
|
license,
|
||||||
|
licenseUrl,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
} = parsePublishApiRequestBody(body));
|
||||||
|
({
|
||||||
|
fileName,
|
||||||
|
filePath,
|
||||||
|
fileExtension,
|
||||||
|
fileType,
|
||||||
|
thumbnailFileName,
|
||||||
|
thumbnailFilePath,
|
||||||
|
thumbnailFileType,
|
||||||
|
} = parsePublishApiRequestFiles(files, true));
|
||||||
|
({ channelName, channelId, channelPassword } = body);
|
||||||
} catch (error) {
|
} 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
|
// check channel authorization
|
||||||
|
@ -89,7 +110,9 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
if (!channelId) {
|
if (!channelId) {
|
||||||
channelId = channelClaimId;
|
channelId = channelClaimId;
|
||||||
}
|
}
|
||||||
return chainquery.claim.queries.resolveClaimInChannel(name, channelClaimId).then(claim => claim.dataValues);
|
return chainquery.claim.queries
|
||||||
|
.resolveClaimInChannel(name, channelClaimId)
|
||||||
|
.then(claim => claim.dataValues);
|
||||||
})
|
})
|
||||||
.then(claim => {
|
.then(claim => {
|
||||||
claimRecord = claim;
|
claimRecord = claim;
|
||||||
|
@ -107,40 +130,60 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
return [null, null];
|
return [null, null];
|
||||||
})
|
})
|
||||||
.then(([fileResult, resolution]) => {
|
.then(([fileResult, resolution]) => {
|
||||||
metadata = Object.assign({}, {
|
metadata = Object.assign(
|
||||||
title : claimRecord.title,
|
{},
|
||||||
|
{
|
||||||
|
title: claimRecord.title,
|
||||||
description: claimRecord.description,
|
description: claimRecord.description,
|
||||||
nsfw : claimRecord.nsfw,
|
nsfw: claimRecord.nsfw,
|
||||||
license : claimRecord.license,
|
license: claimRecord.license,
|
||||||
language : 'en',
|
licenseUrl: claimRecord.license_url,
|
||||||
author : details.title,
|
languages: ['en'],
|
||||||
}, updateMetadata({title, description, nsfw, license}));
|
author: details.title,
|
||||||
|
},
|
||||||
|
updateMetadata({ title, description, nsfw, license, licenseUrl })
|
||||||
|
);
|
||||||
const publishParams = {
|
const publishParams = {
|
||||||
name,
|
name,
|
||||||
bid : '0.01',
|
bid: '0.01',
|
||||||
claim_address: primaryClaimAddress,
|
claim_address: primaryClaimAddress,
|
||||||
channel_name : channelName,
|
channel_name: channelName,
|
||||||
channel_id : channelId,
|
channel_id: channelId,
|
||||||
metadata,
|
title,
|
||||||
|
description,
|
||||||
|
author: details.title,
|
||||||
|
languages: ['en'],
|
||||||
|
license: license || '',
|
||||||
|
license_url: licenseUrl || '',
|
||||||
|
tags: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (nsfw) {
|
||||||
|
publishParams.tags = ['mature'];
|
||||||
|
}
|
||||||
|
|
||||||
if (files.file) {
|
if (files.file) {
|
||||||
if (thumbnailUpdate) {
|
if (thumbnailUpdate) {
|
||||||
// publish new thumbnail
|
// publish new thumbnail
|
||||||
const newThumbnailName = `${name}-${rando()}`;
|
const newThumbnailName = `${name}-${rando()}`;
|
||||||
const newThumbnailParams = createThumbnailPublishParams(filePath, newThumbnailName, license, nsfw);
|
const newThumbnailParams = createThumbnailPublishParams(
|
||||||
|
filePath,
|
||||||
|
newThumbnailName,
|
||||||
|
license,
|
||||||
|
nsfw
|
||||||
|
);
|
||||||
newThumbnailParams['file_path'] = filePath;
|
newThumbnailParams['file_path'] = filePath;
|
||||||
publish(newThumbnailParams, fileName, fileType);
|
publish(newThumbnailParams, fileName, fileType);
|
||||||
|
|
||||||
publishParams['sources'] = resolution.claim.value.stream.source;
|
publishParams['thumbnail'] = `${details.host}/${newThumbnailParams.channel_name}:${
|
||||||
publishParams['thumbnail'] = `${details.host}/${newThumbnailParams.channel_name}:${newThumbnailParams.channel_id}/${newThumbnailName}-thumb.jpg`;
|
newThumbnailParams.channel_id
|
||||||
|
}/${newThumbnailName}-thumb.jpg`;
|
||||||
} else {
|
} else {
|
||||||
publishParams['file_path'] = filePath;
|
publishParams['file_path'] = filePath;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileName = fileResult.fileName;
|
fileName = fileResult.fileName;
|
||||||
fileType = fileResult.fileType;
|
fileType = fileResult.fileType;
|
||||||
publishParams['sources'] = resolution.claim.value.stream.source;
|
|
||||||
publishParams['thumbnail'] = claimRecord.thumbnail_url;
|
publishParams['thumbnail'] = claimRecord.thumbnail_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,17 +194,24 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
publishResult = result;
|
publishResult = result;
|
||||||
|
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(result.certificateId, channelName);
|
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(
|
||||||
|
publishResult.certificateId,
|
||||||
|
channelName
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return chainquery.claim.queries.getShortClaimIdFromLongClaimId(result.claimId, name, result).catch(() => {
|
return chainquery.claim.queries
|
||||||
return result.claimId.slice(0, 1);
|
.getShortClaimIdFromLongClaimId(publishResult.claimId, name, publishResult)
|
||||||
|
.catch(() => {
|
||||||
|
return publishResult.claimId.slice(0, 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(shortId => {
|
.then(shortId => {
|
||||||
let canonicalUrl;
|
let canonicalUrl;
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
canonicalUrl = createCanonicalLink({ asset: { ...publishResult, channelShortId: shortId } });
|
canonicalUrl = createCanonicalLink({
|
||||||
|
asset: { ...publishResult, channelShortId: shortId },
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
canonicalUrl = createCanonicalLink({ asset: { ...publishResult, shortId } });
|
canonicalUrl = createCanonicalLink({ asset: { ...publishResult, shortId } });
|
||||||
}
|
}
|
||||||
|
@ -173,17 +223,17 @@ const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {claimId} = publishResult;
|
const { claimId } = publishResult;
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'update successful',
|
message: 'update successful',
|
||||||
data : {
|
data: {
|
||||||
name,
|
name,
|
||||||
claimId,
|
claimId,
|
||||||
url : `${details.host}${canonicalUrl}`, // for backwards compatability with app
|
url: `${details.host}${canonicalUrl}`, // for backwards compatability with app
|
||||||
showUrl : `${details.host}${canonicalUrl}`,
|
showUrl: `${details.host}${canonicalUrl}`,
|
||||||
serveUrl : `${details.host}${canonicalUrl}${fileExtension}`,
|
serveUrl: `${details.host}${canonicalUrl}${fileExtension}`,
|
||||||
pushTo : canonicalUrl,
|
pushTo: canonicalUrl,
|
||||||
claimData: publishResult,
|
claimData: publishResult,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
const logger = require('winston');
|
||||||
|
|
||||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const db = require('../../../../models');
|
const { getFileListFileByOutpoint } = require('server/lbrynet');
|
||||||
|
|
||||||
|
const chainquery = require('chainquery').default;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -10,18 +14,24 @@ const db = require('../../../../models');
|
||||||
const fileAvailability = ({ ip, originalUrl, params }, res) => {
|
const fileAvailability = ({ ip, originalUrl, params }, res) => {
|
||||||
const name = params.name;
|
const name = params.name;
|
||||||
const claimId = params.claimId;
|
const claimId = params.claimId;
|
||||||
db.File
|
logger.verbose(`fileAvailability params: name:${name} claimId:${claimId}`);
|
||||||
.findOne({
|
// TODO: we probably eventually want to check the publishCache for the claimId too,
|
||||||
where: {
|
// and shop the outpoint to file_list.
|
||||||
name,
|
return chainquery.claim.queries
|
||||||
claimId,
|
.resolveClaim(name, claimId)
|
||||||
},
|
.then(result => {
|
||||||
|
return `${result.dataValues.transaction_hash_id}:${result.dataValues.vout}`;
|
||||||
|
})
|
||||||
|
.then(outpoint => {
|
||||||
|
logger.debug(`fileAvailability: outpoint: ${outpoint}`);
|
||||||
|
return getFileListFileByOutpoint(outpoint);
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result) {
|
if (result && result[0]) {
|
||||||
return res.status(200).json({success: true, data: true});
|
return res.status(200).json({ success: true, data: true });
|
||||||
|
} else {
|
||||||
|
res.status(200).json({ success: true, data: false });
|
||||||
}
|
}
|
||||||
res.status(200).json({success: true, data: false});
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
handleErrorResponse(originalUrl, ip, error, res);
|
handleErrorResponse(originalUrl, ip, error, res);
|
||||||
|
|
|
@ -15,9 +15,20 @@ const BLOCKED_CLAIM = 'BLOCKED_CLAIM';
|
||||||
const NO_FILE = 'NO_FILE';
|
const NO_FILE = 'NO_FILE';
|
||||||
const CONTENT_UNAVAILABLE = 'CONTENT_UNAVAILABLE';
|
const CONTENT_UNAVAILABLE = 'CONTENT_UNAVAILABLE';
|
||||||
|
|
||||||
const { publishing: { serveOnlyApproved, approvedChannels } } = require('@config/siteConfig');
|
const {
|
||||||
|
publishing: { serveOnlyApproved, approvedChannels },
|
||||||
|
} = require('@config/siteConfig');
|
||||||
|
|
||||||
const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId, originalUrl, ip, res, headers) => {
|
const getClaimIdAndServeAsset = (
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
claimName,
|
||||||
|
claimId,
|
||||||
|
originalUrl,
|
||||||
|
ip,
|
||||||
|
res,
|
||||||
|
headers
|
||||||
|
) => {
|
||||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||||
.then(fullClaimId => {
|
.then(fullClaimId => {
|
||||||
claimId = fullClaimId;
|
claimId = fullClaimId;
|
||||||
|
@ -39,24 +50,33 @@ const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId
|
||||||
.then(claim => {
|
.then(claim => {
|
||||||
let claimDataValues = claim.dataValues;
|
let claimDataValues = claim.dataValues;
|
||||||
|
|
||||||
if (serveOnlyApproved && !isApprovedChannel({ longId: claimDataValues.publisher_id || claimDataValues.certificateId }, approvedChannels)) {
|
if (
|
||||||
|
serveOnlyApproved &&
|
||||||
|
!isApprovedChannel(
|
||||||
|
{ longId: claimDataValues.publisher_id || claimDataValues.certificateId },
|
||||||
|
approvedChannels
|
||||||
|
)
|
||||||
|
) {
|
||||||
throw new Error(CONTENT_UNAVAILABLE);
|
throw new Error(CONTENT_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outpoint = claimDataValues.outpoint || `${claimDataValues.transaction_hash_id}:${claimDataValues.vout}`;
|
let outpoint =
|
||||||
|
claimDataValues.outpoint ||
|
||||||
|
`${claimDataValues.transaction_hash_id}:${claimDataValues.vout}`;
|
||||||
logger.debug('Outpoint:', outpoint);
|
logger.debug('Outpoint:', outpoint);
|
||||||
return db.Blocked.isNotBlocked(outpoint).then(() => {
|
return db.Blocked.isNotBlocked(outpoint)
|
||||||
|
// .then(() => {
|
||||||
// If content was found, is approved, and not blocked - log a view.
|
// If content was found, is approved, and not blocked - log a view.
|
||||||
if (headers && headers['user-agent'] && /LBRY/.test(headers['user-agent']) === false) {
|
// if (headers && headers['user-agent'] && /LBRY/.test(headers['user-agent']) === false) {
|
||||||
db.Views.create({
|
// db.Views.create({
|
||||||
time : Date.now(),
|
// time: Date.now(),
|
||||||
isChannel : false,
|
// isChannel: false,
|
||||||
claimId : claimDataValues.claim_id || claimDataValues.claimId,
|
// claimId: claimDataValues.claim_id || claimDataValues.claimId,
|
||||||
publisherId: claimDataValues.publisher_id || claimDataValues.certificateId,
|
// publisherId: claimDataValues.publisher_id || claimDataValues.certificateId,
|
||||||
ip,
|
// ip,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return db.File.findOne({
|
return db.File.findOne({
|
||||||
|
@ -70,7 +90,7 @@ const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId
|
||||||
if (!fileRecord) {
|
if (!fileRecord) {
|
||||||
throw NO_FILE;
|
throw NO_FILE;
|
||||||
}
|
}
|
||||||
serveFile(fileRecord.dataValues, res);
|
serveFile(fileRecord.dataValues, res, originalUrl);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error === NO_CLAIM) {
|
if (error === NO_CLAIM) {
|
||||||
|
@ -98,7 +118,8 @@ const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId
|
||||||
logger.debug('claim was blocked');
|
logger.debug('claim was blocked');
|
||||||
return res.status(451).json({
|
return res.status(451).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
message:
|
||||||
|
'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.com/faq/dmca',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error === NO_FILE) {
|
if (error === NO_FILE) {
|
||||||
|
|
|
@ -1,19 +1,68 @@
|
||||||
const logger = require('winston');
|
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
|
||||||
|
try {
|
||||||
|
originalUrl
|
||||||
|
.split('?')[1]
|
||||||
|
.split('&')
|
||||||
|
.map(pair => {
|
||||||
|
if (pair.includes('=')) {
|
||||||
|
let parr = pair.split('=');
|
||||||
|
queryObject[parr[0]] = parr[1];
|
||||||
|
} else queryObject[pair] = true;
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
const serveFile = ({ filePath, fileType }, res) => {
|
|
||||||
if (!fileType) {
|
if (!fileType) {
|
||||||
logger.error(`no fileType provided for ${filePath}`);
|
logger.error(`no fileType provided for ${filePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mediaType = fileType ? fileType.substr(0, fileType.indexOf('/')) : '';
|
||||||
|
const transform =
|
||||||
|
mediaType === 'image' &&
|
||||||
|
queryObject.hasOwnProperty('h') &&
|
||||||
|
queryObject.hasOwnProperty('w') &&
|
||||||
|
dynamicEnabled;
|
||||||
|
|
||||||
const sendFileOptions = {
|
const sendFileOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Content-Type-Options' : 'nosniff',
|
'X-Content-Type-Options': 'nosniff',
|
||||||
'Content-Type' : fileType,
|
'Content-Type': fileType,
|
||||||
'Access-Control-Allow-Origin' : '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
|
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
logger.debug(`fileOptions for ${filePath}:`, sendFileOptions);
|
logger.debug(`fileOptions for ${filePath}:`, sendFileOptions);
|
||||||
|
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);
|
res.status(200).sendFile(filePath, sendFileOptions);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = serveFile;
|
module.exports = serveFile;
|
||||||
|
|
76
server/controllers/assets/utils/transformImage.js
Normal file
76
server/controllers/assets/utils/transformImage.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
const gm = require('gm');
|
||||||
|
const logger = require('winston');
|
||||||
|
const imageMagick = gm.subClass({ imageMagick: true });
|
||||||
|
const { getImageHeightAndWidth } = require('../../../utils/imageProcessing');
|
||||||
|
|
||||||
|
module.exports = function transformImage(path, queryObj) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let { h: cHeight = null } = queryObj;
|
||||||
|
let { w: cWidth = null } = queryObj;
|
||||||
|
let { t: transform = null } = queryObj;
|
||||||
|
let { x: xOrigin = null } = queryObj;
|
||||||
|
let { y: yOrigin = null } = queryObj;
|
||||||
|
let oHeight,
|
||||||
|
oWidth = null;
|
||||||
|
try {
|
||||||
|
getImageHeightAndWidth(path).then(hwarr => {
|
||||||
|
oHeight = hwarr[0];
|
||||||
|
oWidth = hwarr[1];
|
||||||
|
// conditional logic here
|
||||||
|
if (transform === 'crop') {
|
||||||
|
resolve(_cropCenter(path, cWidth, cHeight, oWidth, oHeight));
|
||||||
|
} else if (transform === 'stretch') {
|
||||||
|
imageMagick(path)
|
||||||
|
.resize(cWidth, cHeight, '!')
|
||||||
|
.toBuffer(null, (err, buf) => {
|
||||||
|
resolve(buf);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// resize scaled
|
||||||
|
imageMagick(path)
|
||||||
|
.resize(cWidth, cHeight)
|
||||||
|
.toBuffer(null, (err, buf) => {
|
||||||
|
resolve(buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(e);
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function _cropCenter(path, cropWidth, cropHeight, originalWidth, originalHeight) {
|
||||||
|
let oAspect = originalWidth / originalHeight;
|
||||||
|
let cAspect = cropWidth / cropHeight;
|
||||||
|
let resizeX,
|
||||||
|
resizeY,
|
||||||
|
xpoint,
|
||||||
|
ypoint = null;
|
||||||
|
|
||||||
|
if (oAspect >= cAspect) {
|
||||||
|
// if crop is narrower aspect than original
|
||||||
|
resizeY = cropHeight;
|
||||||
|
xpoint = (oAspect * cropHeight) / 2 - cropWidth / 2;
|
||||||
|
ypoint = 0;
|
||||||
|
} else {
|
||||||
|
// if crop is wider aspect than original
|
||||||
|
resizeX = cropWidth;
|
||||||
|
xpoint = 0;
|
||||||
|
ypoint = cropWidth / oAspect / 2 - cropHeight / 2;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
imageMagick(path)
|
||||||
|
.resize(resizeX, resizeY)
|
||||||
|
.crop(cropWidth, cropHeight, xpoint, ypoint)
|
||||||
|
.toBuffer(null, (err, buf) => {
|
||||||
|
resolve(buf);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(e);
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -20,10 +20,7 @@ const { setupBlockList } = require('./utils/blockList');
|
||||||
const speechPassport = require('./speechPassport');
|
const speechPassport = require('./speechPassport');
|
||||||
const processTrending = require('./utils/processTrending');
|
const processTrending = require('./utils/processTrending');
|
||||||
|
|
||||||
const {
|
const { setRouteDataInContextMiddleware } = require('./middleware/httpContextMiddleware');
|
||||||
logMetricsMiddleware,
|
|
||||||
setRouteDataInContextMiddleware,
|
|
||||||
} = require('./middleware/logMetricsMiddleware');
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
details: { port: PORT, blockListEndpoint },
|
details: { port: PORT, blockListEndpoint },
|
||||||
|
@ -75,7 +72,7 @@ function Server() {
|
||||||
res
|
res
|
||||||
.status(403)
|
.status(403)
|
||||||
.send(
|
.send(
|
||||||
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.io/">https://chat.lbry.io/</a>'
|
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.com/">https://chat.lbry.com/</a>'
|
||||||
);
|
);
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,7 +142,7 @@ function Server() {
|
||||||
|
|
||||||
app[routeMethod](
|
app[routeMethod](
|
||||||
routePath,
|
routePath,
|
||||||
logMetricsMiddleware,
|
// logMetricsMiddleware,
|
||||||
setRouteDataInContextMiddleware(routePath, routeData),
|
setRouteDataInContextMiddleware(routePath, routeData),
|
||||||
...controllers
|
...controllers
|
||||||
);
|
);
|
||||||
|
@ -195,7 +192,7 @@ function Server() {
|
||||||
'Continuing with default LBRY blocklist api endpoint. \n ' +
|
'Continuing with default LBRY blocklist api endpoint. \n ' +
|
||||||
'(Specify /"blockListEndpoint" : ""/ to disable.'
|
'(Specify /"blockListEndpoint" : ""/ to disable.'
|
||||||
);
|
);
|
||||||
finalBlockListEndpoint = 'https://api.lbry.io/file/list_blocked';
|
finalBlockListEndpoint = 'https://api.lbry.com/file/list_blocked';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info(`Peforming updates...`);
|
logger.info(`Peforming updates...`);
|
||||||
|
|
|
@ -53,13 +53,34 @@ module.exports = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async abandonClaim({ claimId }) {
|
getFileListFileByOutpoint(outpoint) {
|
||||||
logger.debug(`lbryApi >> Abandon claim "${claimId}"`);
|
logger.debug(`lbryApi >> Getting File_List for "${outpoint}"`);
|
||||||
const gaStartTime = Date.now();
|
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({ outpoint }) {
|
||||||
|
logger.debug(`lbryApi >> Abandon claim "${outpoint}"`);
|
||||||
|
const gaStartTime = Date.now();
|
||||||
|
const [txid, nout] = outpoint.split(':');
|
||||||
try {
|
try {
|
||||||
const abandon = await axios.post(lbrynetUri, {
|
const abandon = await axios.post(lbrynetUri, {
|
||||||
method: 'claim_abandon',
|
method: 'stream_abandon',
|
||||||
params: { claim_id: claimId },
|
params: { txid: txid, nout: Number(nout) },
|
||||||
});
|
});
|
||||||
sendGATimingEvent('lbrynet', 'abandonClaim', 'ABANDON_CLAIM', gaStartTime, Date.now());
|
sendGATimingEvent('lbrynet', 'abandonClaim', 'ABANDON_CLAIM', gaStartTime, Date.now());
|
||||||
return abandon.data;
|
return abandon.data;
|
||||||
|
@ -93,7 +114,7 @@ module.exports = {
|
||||||
axios
|
axios
|
||||||
.post(lbrynetUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'resolve',
|
method: 'resolve',
|
||||||
params: { uri },
|
params: { urls: uri },
|
||||||
})
|
})
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
sendGATimingEvent('lbrynet', 'resolveUri', 'RESOLVE', gaStartTime, Date.now());
|
sendGATimingEvent('lbrynet', 'resolveUri', 'RESOLVE', gaStartTime, Date.now());
|
||||||
|
@ -133,7 +154,7 @@ module.exports = {
|
||||||
Date.now()
|
Date.now()
|
||||||
);
|
);
|
||||||
if (data.result) {
|
if (data.result) {
|
||||||
resolve(data.result.download_directory);
|
resolve(data.result.download_dir);
|
||||||
} else {
|
} else {
|
||||||
return new Error(
|
return new Error(
|
||||||
'Successfully connected to lbry daemon, but unable to retrieve the download directory.'
|
'Successfully connected to lbry daemon, but unable to retrieve the download directory.'
|
||||||
|
@ -152,10 +173,10 @@ module.exports = {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbrynetUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'channel_new',
|
method: 'channel_create',
|
||||||
params: {
|
params: {
|
||||||
channel_name: name,
|
name: name,
|
||||||
amount: publishing.channelClaimBidAmount,
|
bid: publishing.channelClaimBidAmount,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
|
@ -1,28 +1,52 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { publishing: { publishingChannelWhitelist } } = require('@config/siteConfig');
|
const {
|
||||||
|
publishing: { publishingChannelWhitelist },
|
||||||
|
} = require('@config/siteConfig');
|
||||||
const ipBanFile = './site/config/ipBan.txt';
|
const ipBanFile = './site/config/ipBan.txt';
|
||||||
const forbiddenMessage = '<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.io/">https://chat.lbry.io/</a>';
|
const ipWhitelist = './site/config/ipWhitelist.txt';
|
||||||
|
const forbiddenMessage =
|
||||||
|
'<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.com/">https://chat.lbry.com/</a>';
|
||||||
|
const maxPublishesInTenMinutes = 20;
|
||||||
let ipCounts = {};
|
let ipCounts = {};
|
||||||
let blockedAddresses = [];
|
let blockedAddresses = [];
|
||||||
|
let whitelistedAddresses = [];
|
||||||
|
|
||||||
if (fs.existsSync(ipBanFile)) {
|
if (fs.existsSync(ipBanFile)) {
|
||||||
const lineReader = require('readline').createInterface({
|
const lineReader = require('readline').createInterface({
|
||||||
input: require('fs').createReadStream(ipBanFile),
|
input: require('fs').createReadStream(ipBanFile),
|
||||||
});
|
});
|
||||||
|
|
||||||
lineReader.on('line', (line) => {
|
lineReader.on('line', line => {
|
||||||
if (line && line !== '') {
|
if (line && line !== '') {
|
||||||
blockedAddresses.push(line);
|
blockedAddresses.push(line);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a file called ipWhitelist.txt exists
|
||||||
|
// Please comment above each whitelisted IP why/who/when etc
|
||||||
|
// # Jim because he's awesome - January 2018
|
||||||
|
if (fs.existsSync(ipWhitelist)) {
|
||||||
|
const lineReader = require('readline').createInterface({
|
||||||
|
input: require('fs').createReadStream(ipWhitelist),
|
||||||
|
});
|
||||||
|
|
||||||
|
lineReader.on('line', line => {
|
||||||
|
if (line && line !== '' && line[0] !== '#') {
|
||||||
|
whitelistedAddresses.push(line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const autoblockPublishMiddleware = (req, res, next) => {
|
const autoblockPublishMiddleware = (req, res, next) => {
|
||||||
let ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress).split(/,\s?/)[0];
|
let ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress).split(/,\s?/)[0];
|
||||||
|
|
||||||
|
if (whitelistedAddresses.indexOf(ip) !== -1) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (blockedAddresses.indexOf(ip) !== -1) {
|
if (blockedAddresses.indexOf(ip) !== -1) {
|
||||||
res.status(403).send(forbiddenMessage);
|
res.status(403).send(forbiddenMessage);
|
||||||
res.end();
|
res.end();
|
||||||
|
@ -30,7 +54,7 @@ const autoblockPublishMiddleware = (req, res, next) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = ipCounts[ip] = (ipCounts[ip] || 0) + 1;
|
let count = (ipCounts[ip] = (ipCounts[ip] || 0) + 1);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ipCounts[ip]) {
|
if (ipCounts[ip]) {
|
||||||
|
@ -41,7 +65,7 @@ const autoblockPublishMiddleware = (req, res, next) => {
|
||||||
}
|
}
|
||||||
}, 600000 /* 10 minute retainer */);
|
}, 600000 /* 10 minute retainer */);
|
||||||
|
|
||||||
if (count === 10) {
|
if (count === maxPublishesInTenMinutes) {
|
||||||
logger.error(`Banning IP: ${ip}`);
|
logger.error(`Banning IP: ${ip}`);
|
||||||
blockedAddresses.push(ip);
|
blockedAddresses.push(ip);
|
||||||
res.status(403).send(forbiddenMessage);
|
res.status(403).send(forbiddenMessage);
|
||||||
|
|
13
server/middleware/httpContextMiddleware.js
Normal file
13
server/middleware/httpContextMiddleware.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
const httpContext = require('express-http-context');
|
||||||
|
|
||||||
|
function setRouteDataInContextMiddleware(routePath, routeData) {
|
||||||
|
return function(req, res, next) {
|
||||||
|
httpContext.set('routePath', routePath);
|
||||||
|
httpContext.set('routeData', routeData);
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setRouteDataInContextMiddleware,
|
||||||
|
};
|
|
@ -388,7 +388,9 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.fetchClaim(name, claimId)
|
this.fetchClaim(name, claimId)
|
||||||
.then(claim => {
|
.then(claim => {
|
||||||
logger.info('resolveClaim claims:', claim);
|
logger.debug(
|
||||||
|
`resolveClaim: ${name}, ${claimId}, -> certificateId: ${claim && claim.certificateId}`
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
serveOnlyApproved &&
|
serveOnlyApproved &&
|
||||||
!isApprovedChannel({ longId: claim.certificateId }, approvedChannels)
|
!isApprovedChannel({ longId: claim.certificateId }, approvedChannels)
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
const db = require('../index.js');
|
const db = require('../index.js');
|
||||||
|
|
||||||
const createClaimRecordDataAfterPublish = (certificateId, channelName, fileName, fileType, publishParams, publishResults) => {
|
const createClaimRecordDataAfterPublish = (
|
||||||
|
certificateId,
|
||||||
|
channelName,
|
||||||
|
fileName,
|
||||||
|
fileType,
|
||||||
|
publishParams,
|
||||||
|
publishResultsOutput
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
metadata: {
|
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
nsfw,
|
nsfw,
|
||||||
},
|
|
||||||
claim_address: address,
|
claim_address: address,
|
||||||
bid: amount,
|
bid: amount,
|
||||||
} = publishParams;
|
} = publishParams;
|
||||||
|
|
||||||
const {
|
const { claim_id: claimId, txid, nout } = publishResultsOutput;
|
||||||
claim_id: claimId,
|
|
||||||
txid,
|
|
||||||
nout,
|
|
||||||
} = publishResults;
|
|
||||||
|
|
||||||
return db.Claim.getCurrentHeight()
|
return db.Claim.getCurrentHeight().then(height => {
|
||||||
.then(height => {
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
claimId,
|
claimId,
|
||||||
|
@ -28,7 +28,7 @@ const createClaimRecordDataAfterPublish = (certificateId, channelName, fileName,
|
||||||
description,
|
description,
|
||||||
address,
|
address,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
outpoint : `${txid}:${nout}`,
|
outpoint: `${txid}:${nout}`,
|
||||||
height,
|
height,
|
||||||
contentType: fileType,
|
contentType: fileType,
|
||||||
nsfw,
|
nsfw,
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
const getMediaDimensions = require('../../utils/getMediaDimensions.js');
|
const getMediaDimensions = require('../../utils/getMediaDimensions.js');
|
||||||
|
|
||||||
async function createFileRecordDataAfterGet (resolveResult, getResult) {
|
async function createFileRecordDataAfterGet(resolveResult, getResult) {
|
||||||
const {
|
const { name, claimId, outpoint, contentType: fileType } = resolveResult;
|
||||||
name,
|
|
||||||
claimId,
|
|
||||||
outpoint,
|
|
||||||
contentType: fileType,
|
|
||||||
} = resolveResult;
|
|
||||||
|
|
||||||
const {
|
const { file_name: fileName, download_path: filePath } = getResult;
|
||||||
file_name: fileName,
|
|
||||||
download_path: filePath,
|
|
||||||
} = getResult;
|
|
||||||
|
|
||||||
const {
|
const { height: fileHeight, width: fileWidth } = await getMediaDimensions(fileType, filePath);
|
||||||
height: fileHeight,
|
|
||||||
width: fileWidth,
|
|
||||||
} = await getMediaDimensions(fileType, filePath);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
|
@ -30,22 +19,17 @@ async function createFileRecordDataAfterGet (resolveResult, getResult) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createFileRecordDataAfterPublish (fileName, fileType, publishParams, publishResults) {
|
async function createFileRecordDataAfterPublish(
|
||||||
const {
|
fileName,
|
||||||
name,
|
fileType,
|
||||||
file_path: filePath,
|
publishParams,
|
||||||
} = publishParams;
|
publishResultsOutput
|
||||||
|
) {
|
||||||
|
const { name, file_path: filePath } = publishParams;
|
||||||
|
|
||||||
const {
|
const { claim_id: claimId, txid, nout } = publishResultsOutput;
|
||||||
claim_id: claimId,
|
|
||||||
txid,
|
|
||||||
nout,
|
|
||||||
} = publishResults;
|
|
||||||
|
|
||||||
const {
|
const { height: fileHeight, width: fileWidth } = await getMediaDimensions(fileType, filePath);
|
||||||
height: fileHeight,
|
|
||||||
width: fileWidth,
|
|
||||||
} = await getMediaDimensions(fileType, filePath);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createSagaMiddleware from 'redux-saga';
|
||||||
import { call } from 'redux-saga/effects';
|
import { call } from 'redux-saga/effects';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import * as httpContext from 'express-http-context';
|
import * as httpContext from 'express-http-context';
|
||||||
|
import logger from 'winston';
|
||||||
|
|
||||||
import Reducers from '@reducers';
|
import Reducers from '@reducers';
|
||||||
import GAListener from '@components/GAListener';
|
import GAListener from '@components/GAListener';
|
||||||
|
@ -92,6 +93,7 @@ export default (req, res) => {
|
||||||
const preloadedState = store.getState();
|
const preloadedState = store.getState();
|
||||||
|
|
||||||
// send the rendered page back to the client
|
// send the rendered page back to the client
|
||||||
|
|
||||||
res.send(renderFullPage(helmet, html, preloadedState));
|
res.send(renderFullPage(helmet, html, preloadedState));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,8 +123,8 @@ export default (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canonicalUrl && canonicalUrl !== req.originalUrl) {
|
if (canonicalUrl && canonicalUrl !== req.originalUrl) {
|
||||||
console.log(`redirecting ${req.originalUrl} to ${canonicalUrl}`);
|
logger.verbose(`redirecting ${req.originalUrl} to ${canonicalUrl}`);
|
||||||
res.redirect(canonicalUrl);
|
return res.redirect(canonicalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderPage(store);
|
return renderPage(store);
|
||||||
|
|
|
@ -3,7 +3,7 @@ const path = require('path');
|
||||||
|
|
||||||
const bundlePath = path.resolve('./public/bundle/bundle.js');
|
const bundlePath = path.resolve('./public/bundle/bundle.js');
|
||||||
const bundleHash = md5File.sync(bundlePath);
|
const bundleHash = md5File.sync(bundlePath);
|
||||||
const shortBundleHash = bundleHash.substring(0,4);
|
const shortBundleHash = bundleHash.substring(0, 4);
|
||||||
|
|
||||||
module.exports = (helmet, html, preloadedState) => {
|
module.exports = (helmet, html, preloadedState) => {
|
||||||
// take the html and preloadedState and return the full page
|
// take the html and preloadedState and return the full page
|
||||||
|
@ -14,6 +14,7 @@ module.exports = (helmet, html, preloadedState) => {
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="google-site-verification" content="U3240KfVplLZSRCcOHxGuDFQO6eVUXKeFsSD2WJvdLo" />
|
||||||
<!--helmet-->
|
<!--helmet-->
|
||||||
${helmet.title.toString()}
|
${helmet.title.toString()}
|
||||||
${helmet.meta.toString()}
|
${helmet.meta.toString()}
|
||||||
|
@ -27,7 +28,10 @@ module.exports = (helmet, html, preloadedState) => {
|
||||||
<body>
|
<body>
|
||||||
<div id="react-app">${html}</div>
|
<div id="react-app">${html}</div>
|
||||||
<script>
|
<script>
|
||||||
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\\u003c')}
|
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
|
||||||
|
/</g,
|
||||||
|
'\\\u003c'
|
||||||
|
)}
|
||||||
</script>
|
</script>
|
||||||
<script src="/bundle/bundle.js?${shortBundleHash}"></script>
|
<script src="/bundle/bundle.js?${shortBundleHash}"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -25,6 +25,7 @@ const publishingConfig = require('../../controllers/api/config/site/publishing')
|
||||||
const getTorList = require('../../controllers/api/tor');
|
const getTorList = require('../../controllers/api/tor');
|
||||||
const getBlockedList = require('../../controllers/api/blocked');
|
const getBlockedList = require('../../controllers/api/blocked');
|
||||||
const getOEmbedData = require('../../controllers/api/oEmbed');
|
const getOEmbedData = require('../../controllers/api/oEmbed');
|
||||||
|
const cors = require('cors');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// homepage routes
|
// homepage routes
|
||||||
|
@ -43,10 +44,10 @@ export default {
|
||||||
'/api/claim/data/:claimName/:claimId' : { controller: [ torCheckMiddleware, claimData ] },
|
'/api/claim/data/:claimName/:claimId' : { controller: [ torCheckMiddleware, claimData ] },
|
||||||
'/api/claim/get/:name/:claimId' : { controller: [ torCheckMiddleware, claimGet ] },
|
'/api/claim/get/:name/:claimId' : { controller: [ torCheckMiddleware, claimGet ] },
|
||||||
'/api/claim/list/:name' : { controller: [ torCheckMiddleware, claimList ] },
|
'/api/claim/list/:name' : { controller: [ torCheckMiddleware, claimList ] },
|
||||||
'/api/claim/long-id' : { method: 'post', controller: [ torCheckMiddleware, claimLongId ] }, // note: should be a 'get'
|
'/api/claim/long-id' : { method: 'post', controller: [ cors(), torCheckMiddleware, claimLongId ] }, // note: should be a 'get'
|
||||||
'/api/claim/publish' : { method: 'post', controller: [ torCheckMiddleware, autoblockPublishMiddleware, multipartMiddleware, autoblockPublishBodyMiddleware, claimPublish ] },
|
'/api/claim/publish' : { method: 'post', controller: [ cors(), torCheckMiddleware, autoblockPublishMiddleware, multipartMiddleware, autoblockPublishBodyMiddleware, claimPublish ] },
|
||||||
'/api/claim/update' : { method: 'post', controller: [ torCheckMiddleware, multipartMiddleware, claimUpdate ] },
|
'/api/claim/update' : { method: 'post', controller: [ cors(), torCheckMiddleware, multipartMiddleware, claimUpdate ] },
|
||||||
'/api/claim/abandon' : { method: 'post', controller: [ torCheckMiddleware, multipartMiddleware, claimAbandon ] },
|
'/api/claim/abandon' : { method: 'post', controller: [ cors(), torCheckMiddleware, multipartMiddleware, claimAbandon ] },
|
||||||
'/api/claim/resolve/:name/:claimId' : { controller: [ torCheckMiddleware, claimResolve ] },
|
'/api/claim/resolve/:name/:claimId' : { controller: [ torCheckMiddleware, claimResolve ] },
|
||||||
'/api/claim/short-id/:longId/:name' : { controller: [ torCheckMiddleware, claimShortId ] },
|
'/api/claim/short-id/:longId/:name' : { controller: [ torCheckMiddleware, claimShortId ] },
|
||||||
'/api/claim/views/:claimId' : { controller: [ torCheckMiddleware, claimViews ] },
|
'/api/claim/views/:claimId' : { controller: [ torCheckMiddleware, claimViews ] },
|
||||||
|
@ -55,7 +56,7 @@ export default {
|
||||||
// user routes
|
// user routes
|
||||||
'/api/user/password/' : { method: 'put', controller: [ torCheckMiddleware, userPassword ] },
|
'/api/user/password/' : { method: 'put', controller: [ torCheckMiddleware, userPassword ] },
|
||||||
// configs
|
// configs
|
||||||
'/api/config/site/publishing' : { controller: [ torCheckMiddleware, publishingConfig ] },
|
'/api/config/site/publishing' : { controller: [ cors(), torCheckMiddleware, publishingConfig ] },
|
||||||
// tor
|
// tor
|
||||||
'/api/tor' : { controller: [ torCheckMiddleware, getTorList ] },
|
'/api/tor' : { controller: [ torCheckMiddleware, getTorList ] },
|
||||||
// blocked
|
// blocked
|
||||||
|
|
|
@ -2,6 +2,6 @@ module.exports = {
|
||||||
...require('./pages').default,
|
...require('./pages').default,
|
||||||
...require('./api').default,
|
...require('./api').default,
|
||||||
...require('./auth').default,
|
...require('./auth').default,
|
||||||
...require('./assets').default,
|
// ...require('./assets').default,
|
||||||
...require('./fallback').default,
|
...require('./fallback').default,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,9 @@ const PassportLocalStrategy = require('passport-local').Strategy;
|
||||||
const { createChannel } = require('../../lbrynet');
|
const { createChannel } = require('../../lbrynet');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../../models');
|
const db = require('../../models');
|
||||||
const { publishing: { closedRegistration } } = require('@config/siteConfig');
|
const {
|
||||||
|
publishing: { closedRegistration },
|
||||||
|
} = require('@config/siteConfig');
|
||||||
|
|
||||||
module.exports = new PassportLocalStrategy(
|
module.exports = new PassportLocalStrategy(
|
||||||
{
|
{
|
||||||
|
@ -28,19 +30,23 @@ module.exports = new PassportLocalStrategy(
|
||||||
logger.verbose('userData >', userData);
|
logger.verbose('userData >', userData);
|
||||||
// create user record
|
// create user record
|
||||||
const channelData = {
|
const channelData = {
|
||||||
channelName : `@${username}`,
|
channelName: `@${username}`,
|
||||||
channelClaimId: tx.claim_id,
|
channelClaimId: tx.outputs[0].claim_id,
|
||||||
};
|
};
|
||||||
logger.verbose('channelData >', channelData);
|
logger.verbose('channelData >', channelData);
|
||||||
// create certificate record
|
// create certificate record
|
||||||
const certificateData = {
|
const certificateData = {
|
||||||
claimId: tx.claim_id,
|
claimId: tx.outputs[0].claim_id,
|
||||||
name : `@${username}`,
|
name: `@${username}`,
|
||||||
// address,
|
// address,
|
||||||
};
|
};
|
||||||
logger.verbose('certificateData >', certificateData);
|
logger.verbose('certificateData >', certificateData);
|
||||||
// save user and certificate to db
|
// save user and certificate to db
|
||||||
return Promise.all([db.User.create(userData), db.Channel.create(channelData), db.Certificate.create(certificateData)]);
|
return Promise.all([
|
||||||
|
db.User.create(userData),
|
||||||
|
db.Channel.create(channelData),
|
||||||
|
db.Certificate.create(certificateData),
|
||||||
|
]);
|
||||||
})
|
})
|
||||||
.then(([newUser, newChannel, newCertificate]) => {
|
.then(([newUser, newChannel, newCertificate]) => {
|
||||||
logger.verbose('user and certificate successfully created');
|
logger.verbose('user and certificate successfully created');
|
||||||
|
@ -54,7 +60,10 @@ module.exports = new PassportLocalStrategy(
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.verbose('user and certificate successfully associated');
|
logger.verbose('user and certificate successfully associated');
|
||||||
return db.Certificate.getShortChannelIdFromLongChannelId(userInfo.channelClaimId, userInfo.channelName);
|
return db.Certificate.getShortChannelIdFromLongChannelId(
|
||||||
|
userInfo.channelClaimId,
|
||||||
|
userInfo.channelName
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.then(shortChannelId => {
|
.then(shortChannelId => {
|
||||||
userInfo['shortChannelId'] = shortChannelId;
|
userInfo['shortChannelId'] = shortChannelId;
|
||||||
|
|
32
server/utils/awaitFileSize.js
Normal file
32
server/utils/awaitFileSize.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
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 => {
|
||||||
|
const { items: fileInfos } = result;
|
||||||
|
const fileInfo = fileInfos[0];
|
||||||
|
logger.debug('File List Result', fileInfo);
|
||||||
|
if (fileInfo.completed === true || fileInfo.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;
|
|
@ -3,7 +3,7 @@ const logger = require('winston');
|
||||||
const config = require('@config/loggerConfig');
|
const config = require('@config/loggerConfig');
|
||||||
const { logLevel } = config;
|
const { logLevel } = config;
|
||||||
|
|
||||||
function configureLogging () {
|
function configureLogging() {
|
||||||
logger.info('configuring winston logger...');
|
logger.info('configuring winston logger...');
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return logger.warn('No logger config found');
|
return logger.warn('No logger config found');
|
||||||
|
@ -14,12 +14,12 @@ function configureLogging () {
|
||||||
// configure the winston logger
|
// configure the winston logger
|
||||||
logger.configure({
|
logger.configure({
|
||||||
transports: [
|
transports: [
|
||||||
new (logger.transports.Console)({
|
new logger.transports.Console({
|
||||||
level : logLevel || 'debug',
|
level: logLevel || 'debug',
|
||||||
timestamp : false,
|
timestamp: true,
|
||||||
colorize : true,
|
colorize: true,
|
||||||
prettyPrint : true,
|
prettyPrint: true,
|
||||||
handleExceptions : true,
|
handleExceptions: true,
|
||||||
humanReadableUnhandledException: true,
|
humanReadableUnhandledException: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
|
@ -59,5 +59,8 @@ module.exports = async (data, chName = null, chShortId = null) => {
|
||||||
host,
|
host,
|
||||||
pending: Boolean(dataVals.height === 0),
|
pending: Boolean(dataVals.height === 0),
|
||||||
blocked: blocked,
|
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['@clientutils'] = resolve(`${DEFAULT_ROOT}/utils`);
|
||||||
// moduleAliases['@serverutils'] = resolve('server/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
|
// create specific aliases for locally defined components in the following folders
|
||||||
moduleAliases = addAliasesForCustomComponentFolder('containers', moduleAliases);
|
moduleAliases = addAliasesForCustomComponentFolder('containers', moduleAliases);
|
||||||
moduleAliases = addAliasesForCustomComponentFolder('components', moduleAliases);
|
moduleAliases = addAliasesForCustomComponentFolder('components', moduleAliases);
|
||||||
|
@ -53,7 +56,6 @@ module.exports = () => {
|
||||||
moduleAliases['@sagas'] = resolve(`${DEFAULT_ROOT}/sagas`);
|
moduleAliases['@sagas'] = resolve(`${DEFAULT_ROOT}/sagas`);
|
||||||
moduleAliases['@app'] = resolve(`${DEFAULT_ROOT}/app.js`);
|
moduleAliases['@app'] = resolve(`${DEFAULT_ROOT}/app.js`);
|
||||||
|
|
||||||
|
|
||||||
// return finished aliases
|
// return finished aliases
|
||||||
return moduleAliases;
|
return moduleAliases;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue