diff --git a/client/scss/_asset-preview.scss b/client/scss/_asset-preview.scss index 78f26e4b..a9d0cb48 100644 --- a/client/scss/_asset-preview.scss +++ b/client/scss/_asset-preview.scss @@ -1,29 +1,89 @@ .asset-preview { - position: relative; + display: flex; + flex-direction: column; background: $card-color; - padding: $thin-padding; color: $text-color; width: 240px; border: $subtle-border; - height: 280px; + height: 256px; &:hover { - border: 1px solid $highlight-border-color; + border-color: $highlight-border-color; 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 { + height: 100%; + padding: $thin-padding; display: flex; flex-direction: column; justify-content: space-between; - height: 7.3em; } .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; text-overflow: ellipsis; 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 { @@ -34,22 +94,3 @@ padding: $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; -} diff --git a/client/scss/_channel-claims-display.scss b/client/scss/_channel-claims-display.scss index 3ca6baba..ebca63d8 100644 --- a/client/scss/_channel-claims-display.scss +++ b/client/scss/_channel-claims-display.scss @@ -1,7 +1,7 @@ .channel-claims-display { width: 100%; display: grid; - grid-gap: $thin-padding; + grid-gap: $tertiary-padding; align-content: space-around; @media (min-width: $break-point-x-large) { grid-template-columns: 1fr 1fr 1fr 1fr 1fr; diff --git a/client/src/components/AssetPreview/index.jsx b/client/src/components/AssetPreview/index.jsx index 79060417..2105a56a 100644 --- a/client/src/components/AssetPreview/index.jsx +++ b/client/src/components/AssetPreview/index.jsx @@ -4,9 +4,23 @@ import createCanonicalLink from '@globalutils/createCanonicalLink'; import * as Icon from 'react-feather'; const AssetPreview = ({ defaultThumbnail, claimData }) => { - const {name, fileExt, contentType, thumbnail, title, blocked} = claimData; + const {name, fileExt, contentType, thumbnail, title, blocked, transactionTime} = claimData; const showUrl = createCanonicalLink({asset: {...claimData}}); + console.log(transactionTime) const embedUrl = `${showUrl}.${fileExt}`; + const ago = Date.now()/1000 - transactionTime; + const dayInSeconds = 60 * 60 * 24; + const monthInSeconds = dayInSeconds * 30; + const yearInSeconds = dayInSeconds * 365; + let when; + + if (ago < dayInSeconds) { + 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 */ @@ -37,21 +51,32 @@ const AssetPreview = ({ defaultThumbnail, claimData }) => { } else { return ( <Link to={showUrl} className='asset-preview'> - <img - className={'asset-preview__image'} - src={thumb || defaultThumbnail} - alt={name} - /> + <div className='asset-preview__image-box'> + <img + className={'asset-preview__image'} + src={thumb || defaultThumbnail} + alt={name} + /> + </div> + <div className={'asset-preview__label'}> + <div className={'asset-preview__label-text'}> - <p className='asset-preview__title text--medium'>{title}</p> + <p>{title}</p> </div> - <div className={'asset-preview__label-info'}> - <div className={'text--medium'}> - { media === 'image' && <Icon.Image />} - { media === 'text' && <Icon.FileText />} - { media === 'video' && contentType === 'video/mp4' && <Icon.Video />} - { media !== 'image' && media !== 'text' && contentType !== 'video/mp4' && <Icon.File />} + <div className={'asset-preview__label-info '}> + <div className={'asset-preview__label-info-datum'}> + <div className={'svg-icon'}> + { media === 'image' && <Icon.Image />} + { media === 'text' && <Icon.FileText />} + { media === 'video' && contentType === 'video/mp4' && <Icon.Video />} + { media !== 'image' && media !== 'text' && contentType !== 'video/mp4' && <Icon.File />} + </div> + <div>{fileExt}</div> + </div> + + <div className={'asset-preview__label-info-datum'}> + <div>{when}</div> </div> </div> </div> diff --git a/client/src/components/ChannelSelectDropdown/index.jsx b/client/src/components/ChannelSelectDropdown/index.jsx index ae4b1211..2079c05c 100644 --- a/client/src/components/ChannelSelectDropdown/index.jsx +++ b/client/src/components/ChannelSelectDropdown/index.jsx @@ -7,6 +7,9 @@ const ChannelSelectDropdown = ({ selectedChannel, handleSelection, loggedInChann id='channel-name-select' value={selectedChannel} onChange={handleSelection}> + { loggedInChannelName && ( + <option value={loggedInChannelName} >{loggedInChannelName}</option> + )} <option value={LOGIN}>Existing</option> <option value={CREATE}>New</option> </select> diff --git a/docs/setup/conf/lbrynet/lbrynet.service.example b/docs/setup/conf/lbrynet/lbrynet.service.example new file mode 100644 index 00000000..6661b863 --- /dev/null +++ b/docs/setup/conf/lbrynet/lbrynet.service.example @@ -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 + diff --git a/docs/setup/conf/lbrynet/lbrynet.service.template b/docs/setup/conf/lbrynet/lbrynet.service.template new file mode 100644 index 00000000..84682df8 --- /dev/null +++ b/docs/setup/conf/lbrynet/lbrynet.service.template @@ -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 + diff --git a/docs/ubuntuinstall.md b/docs/ubuntuinstall.md index 7ee8954e..6a5660c1 100644 --- a/docs/ubuntuinstall.md +++ b/docs/ubuntuinstall.md @@ -24,6 +24,8 @@ * Lbrynet DAEMON started on ports 3333 and 4444 * 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 ## OS @@ -36,26 +38,27 @@ As root# _create user and add to sudo group_ su - username ``` As username: *paste public key in authorized\_keys* -``` + `cd` + `mkdir .ssh` + `nano ~/.ssh/authorized_keys` -``` ### Prep -Log in as username@domainname or username@ip_address +ssh to username@domainname or username@ip_address - `sudo apt-get update -y` - - `ulimit -n 8192` - - `wget -qO- https://deb.nodesource.com/setup_8.x | sudo -E bash -` + ``` + sudo apt-get update -y + ulimit -n 8192 + 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. @@ -67,7 +70,7 @@ Log in as username@domainname or username@ip_address `git clone https://github.com/{{youraccount}}/spee.ch.git` - `git clone git@github.com:{{youraccount}}/spee.ch` + `git clone git@github.com:{{youraccount}}/spee.ch` * For Publishers and Content creators - stable release @@ -78,24 +81,29 @@ Log in as username@domainname or username@ip_address `chmod 750 -R ~/spee.ch/docs/setup` # 2 Secure the UFW firewall + ## UFW `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 + ## Get Caddy `curl https://getcaddy.com | sudo bash -s personal` ## 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/` - - `cp ~/spee.ch/docs/setup/conf/caddy/Caddyfile.template ~/spee.ch/docs/setup/conf/caddy/Caddyfile` - - `nano ~/spee.ch/docs/setup/conf/caddy/Caddyfile` + ``` + sudo mkdir -p /opt/caddy/logs/ + 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 + ``` ( 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 - `sudo cp ~/spee.ch/docs/setup/conf/caddy/caddy.service /etc/systemd/system/caddy.service` - - `sudo chmod 644 /etc/systemd/system/caddy.service` - - `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 systemctl start caddy` - - `sudo systemctl status caddy` + ``` + sudo cp ~/spee.ch/docs/setup/conf/caddy/caddy.service /etc/systemd/system/caddy.service + sudo chmod 644 /etc/systemd/system/caddy.service + 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 systemctl start caddy + sudo systemctl status caddy + ``` `q` exits @@ -151,7 +155,7 @@ Log in as username@domainname or username@ip_address 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> @@ -165,78 +169,108 @@ Log in as username@domainname or username@ip_address # 5 Get Lbrynet SDK Daemon -## Start tmux - -tmux allows you to run multiple things in different sessions. Useful for manually starting daemons and watching its console logs. - - `tmux` - * `Ctrl+b`, then `d` detaches leaving session running. - * `tmux`, reenters tmux, then - * `Ctrl+b`, `(` goes back to through sessions - ## Get the SDK - `wget -O ~/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip` - `unzip -o -u ~/latest_daemon.zip` + We'll be putting it in /opt/lbry. + + `sudo mkdir /opt/lbry` + + `sudo wget -O /opt/lbry/latest_daemon.zip https://lbry.io/get/lbrynet.linux.zip` + + `sudo unzip -o -u /opt/lbry/latest_daemon.zip -d /opt/lbry` + +## Set up lbrynet to run as systemd service + + We'll soon update the setup scripts. Meanwhile, here's an example lbrynet.service file. Again, fully replace {{USERNAME}} + + ``` + [Unit] +Description="LBRYnet daemon" +After=network.target + +# 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 + +[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). ~$ - `mkdir .lbrynet` - `cd .lbrynet` + `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 - disable_max_key_fee: 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 - -## Start the daemon - `./lbrynet start` - -## Detatch tmux session - `Control + b`, then `d` - - * `tmux` if you want to get back into tmux - - * `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output - `tmux` - - _note: `Control+b`, then `)` while in tmux session to cycle back to your lbrynet session to see output_ + Restart lbrynet sdk: + + `sudo systemctl restart lbrynet` + + `sudo systemctl status lbrynet` + ## 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. 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. - -## Optional/Production: Set up lbrynet to run as a systemd service - - `//coming soon` + `lbrynet account balance` to check your balance after you've sent LBC. # 6 Set up spee.ch ## Build it + `cd spee.ch` ~/spee.ch: @@ -257,7 +291,8 @@ tmux allows you to run multiple things in different sessions. Useful for manuall * Port: 3000 * Site Title: Your Site Name * 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) @@ -270,15 +305,34 @@ tmux allows you to run multiple things in different sessions. Useful for manuall # 7 Production ## 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 -#### Change daemon - * backup wallet (private keys!) to a safe place - * wget daemon from https://github.com/lbryio/lbry/releases - * wget -O ~/your_name_daemon.zip https://your_copied_file_path.zip - * rm ./lbrynet - * unzip -o -u ~/your_name_daemon.zip +#### Update sdk daemon + + * Backup wallet (private keys!) to a safe place. It should be in ~/.local/share/lbry/lbryum/wallets. + * `lbrynet stop` + * Following the instructions in 5: Get the SDK will rename the old daemon and give you the new one. + * `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 diff --git a/server/lbrynet/index.js b/server/lbrynet/index.js index 6259dd0f..caecb74a 100644 --- a/server/lbrynet/index.js +++ b/server/lbrynet/index.js @@ -153,7 +153,7 @@ module.exports = { Date.now() ); if (data.result) { - resolve(data.result.download_directory); + resolve(data.result.download_dir); } else { return new Error( 'Successfully connected to lbry daemon, but unable to retrieve the download directory.'