Merge branch 'master' into comicbook-reader

This commit is contained in:
Baltazar Gomez 2019-05-22 23:05:54 -06:00 committed by GitHub
commit 4eb0131f83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 1406 additions and 1185 deletions

1
.gitignore vendored
View file

@ -6,5 +6,6 @@
/static/locales /static/locales
yarn-error.log yarn-error.log
package-lock.json package-lock.json
.transifexrc
.idea/ .idea/
/build/daemon* /build/daemon*

View file

@ -1,8 +1,8 @@
[main] [main]
host = https://www.transifex.com host = https://www.transifex.com
[lbry-deskop.app-strings] [lbry-desktop.app-strings]
file_filter = dist/locales/<lang>.json file_filter = static/locales/<lang>.json
source_file = dist/locales/en.json source_file = static/locales/en.json
source_lang = en source_lang = en
type = KEYVALUEJSON type = KEYVALUEJSON

View file

@ -4,14 +4,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.32.0] - [Unreleased] ## [0.32.2] - [2019-5-20]
### Fixed ### Fixed
- Upgraded LBRY SDK to 0.37.0 for better network stability
- Better error logging
## [0.32.1] - [2019-5-14]
### Fixed
- Fix analytics on desktop ([#2480](https://github.com/lbryio/lbry-desktop/pull/2480))
- Fix text wrapping on file page ([#2480](https://github.com/lbryio/lbry-desktop/pull/2480))
## [0.32.0] - [2019-5-14]
### Fixed
- Updating claims after they are tipped
- Opening html, markdown, and other text documents
- Opening links from open.lbry.com
### Added ### Added
- New routing setup to allow lbry.tv to use the browser url bar for navigation ([#2408](https://github.com/lbryio/lbry-desktop/pull/2408)) - New routing setup to allow lbry.tv to use the browser url bar for navigation ([#2408](https://github.com/lbryio/lbry-desktop/pull/2408))
- New audio player ([#2406](https://github.com/lbryio/lbry-desktop/pull/2406))
- Always show new suggested subscriptions ([#2541](https://github.com/lbryio/lbry-desktop/pull/2451)) - Always show new suggested subscriptions ([#2541](https://github.com/lbryio/lbry-desktop/pull/2451))
### Changed ### Changed

View file

@ -1,6 +1,6 @@
{ {
"name": "LBRY", "name": "LBRY",
"version": "0.32.1", "version": "0.32.2",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [ "keywords": [
"lbry" "lbry"
@ -40,8 +40,6 @@
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js" "postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
}, },
"dependencies": { "dependencies": {
"@reach/rect": "^0.2.1",
"@reach/tabs": "^0.1.5",
"electron-dl": "^1.11.0", "electron-dl": "^1.11.0",
"electron-log": "^2.2.12", "electron-log": "^2.2.12",
"electron-updater": "^4.0.6", "electron-updater": "^4.0.6",
@ -63,6 +61,8 @@
"@hot-loader/react-dom": "16.8", "@hot-loader/react-dom": "16.8",
"@lbry/color": "^1.0.2", "@lbry/color": "^1.0.2",
"@lbry/components": "^2.7.0", "@lbry/components": "^2.7.0",
"@reach/rect": "^0.2.1",
"@reach/tabs": "^0.1.5",
"@types/three": "^0.93.1", "@types/three": "^0.93.1",
"async-exit-hook": "^2.0.1", "async-exit-hook": "^2.0.1",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
@ -76,7 +76,7 @@
"chalk": "^2.4.2", "chalk": "^2.4.2",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"codemirror": "^5.39.2", "codemirror": "^5.39.2",
"connected-react-router": "^6.3.2", "connected-react-router": "^6.4.0",
"cookie": "^0.3.1", "cookie": "^0.3.1",
"copy-webpack-plugin": "^4.6.0", "copy-webpack-plugin": "^4.6.0",
"country-data": "^0.0.31", "country-data": "^0.0.31",
@ -89,7 +89,7 @@
"devtron": "^1.4.0", "devtron": "^1.4.0",
"dom-scroll-into-view": "^1.2.1", "dom-scroll-into-view": "^1.2.1",
"electron": "4.1.0", "electron": "4.1.0",
"electron-builder": "^20.39.0", "electron-builder": "^20.41.0",
"electron-devtools-installer": "^2.2.4", "electron-devtools-installer": "^2.2.4",
"electron-is-dev": "^0.3.0", "electron-is-dev": "^0.3.0",
"electron-publisher-s3": "^20.8.1", "electron-publisher-s3": "^20.8.1",
@ -149,6 +149,7 @@
"react-paginate": "^5.2.1", "react-paginate": "^5.2.1",
"react-pose": "^4.0.5", "react-pose": "^4.0.5",
"react-redux": "^6.0.1", "react-redux": "^6.0.1",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0", "react-router-dom": "^5.0.0",
"react-simplemde-editor": "^4.0.0", "react-simplemde-editor": "^4.0.0",
"react-toggle": "^4.0.2", "react-toggle": "^4.0.2",
@ -189,7 +190,7 @@
"yarn": "^1.3" "yarn": "^1.3"
}, },
"lbrySettings": { "lbrySettings": {
"lbrynetDaemonVersion": "0.37.0", "lbrynetDaemonVersion": "0.37.1",
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
"lbrynetDaemonDir": "static/daemon", "lbrynetDaemonDir": "static/daemon",
"lbrynetDaemonFileName": "lbrynet" "lbrynetDaemonFileName": "lbrynet"

View file

@ -4,6 +4,7 @@ import * as React from 'react';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import Button from 'component/button'; import Button from 'component/button';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import Native from 'native';
type Props = { type Props = {
children: React.Node, children: React.Node,
@ -29,15 +30,28 @@ class ErrorBoundary extends React.Component<Props, State> {
} }
componentDidCatch(error: { stack: string }) { componentDidCatch(error: { stack: string }) {
let errorMessage = '\n';
// @if TARGET='web'
errorMessage += 'lbry.tv error\n';
errorMessage += window.location.pathname + window.location.search;
this.log(errorMessage);
// @endif
// @if TARGET='app'
Native.getAppVersionInfo().then(({ localVersion }) => {
errorMessage += `version: ${localVersion}\n`;
errorMessage += `page: ${window.location.href.split('.html')[1]}\n`;
errorMessage += `${error.stack}`;
this.log(errorMessage);
});
// @endif
}
log(message) {
declare var app: { env: string }; declare var app: { env: string };
const errorMessage = `
${window.location.pathname + window.location.search}\n
${error.stack}
`;
if (app.env === 'production') { if (app.env === 'production') {
Lbryio.call('event', 'desktop_error', { error_message: errorMessage }); Lbryio.call('event', 'desktop_error', { error_message: message });
} }
} }

View file

@ -1,5 +1,5 @@
// @flow // @flow
import 'babel-polyfill'; import '@babel/polyfill';
import * as React from 'react'; import * as React from 'react';
// @if TARGET='app' // @if TARGET='app'
import { remote } from 'electron'; import { remote } from 'electron';

View file

@ -407,6 +407,7 @@ class PublishForm extends React.PureComponent<Props> {
</header> </header>
<SelectThumbnail <SelectThumbnail
filePath={filePath}
thumbnailPath={thumbnailPath} thumbnailPath={thumbnailPath}
thumbnail={thumbnail} thumbnail={thumbnail}
uploadThumbnailStatus={uploadThumbnailStatus} uploadThumbnailStatus={uploadThumbnailStatus}

View file

@ -2,6 +2,7 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { THUMBNAIL_STATUSES } from 'lbry-redux'; import { THUMBNAIL_STATUSES } from 'lbry-redux';
import * as React from 'react'; import * as React from 'react';
import getMediaType from 'util/get-media-type';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
import FileSelector from 'component/common/file-selector'; import FileSelector from 'component/common/file-selector';
import Button from 'component/button'; import Button from 'component/button';
@ -9,6 +10,7 @@ import ThumbnailMissingImage from './thumbnail-missing.png';
import ThumbnailBrokenImage from './thumbnail-broken.png'; import ThumbnailBrokenImage from './thumbnail-broken.png';
type Props = { type Props = {
filePath: ?string,
thumbnail: ?string, thumbnail: ?string,
formDisabled: boolean, formDisabled: boolean,
uploadThumbnailStatus: string, uploadThumbnailStatus: string,
@ -50,6 +52,7 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
render() { render() {
const { const {
filePath,
thumbnail, thumbnail,
formDisabled, formDisabled,
uploadThumbnailStatus: status, uploadThumbnailStatus: status,
@ -61,6 +64,8 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
const { thumbnailError } = this.state; const { thumbnailError } = this.state;
const isSupportedVideo = getMediaType(null, filePath) === 'video';
let thumbnailSrc; let thumbnailSrc;
if (!thumbnail) { if (!thumbnail) {
thumbnailSrc = ThumbnailMissingImage; thumbnailSrc = ThumbnailMissingImage;
@ -141,9 +146,16 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
<div className="card__actions"> <div className="card__actions">
<Button <Button
button="link" button="link"
label={__('Or enter a URL manually')} label={__('Enter a thumbnail URL')}
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.MANUAL })} onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.MANUAL })}
/> />
{isSupportedVideo && (
<Button
button="link"
label={__('Take a snapshot from your video')}
onClick={() => openModal(MODALS.AUTO_GENERATE_THUMBNAIL, { filePath })}
/>
)}
</div> </div>
)} )}

View file

@ -24,6 +24,10 @@ class AudioVideoViewer extends React.PureComponent<Props> {
const { contentType, poster, claim } = this.props; const { contentType, poster, claim } = this.props;
const { name, claim_id: claimId, txid, nout } = claim; const { name, claim_id: claimId, txid, nout } = claim;
// Quick fix to get file view events on lbry.tv
// Will need to be changed to include time to start
analytics.apiLogView(`${name}#${claimId}`, `${txid}:${nout}`, claimId);
const path = `https://api.piratebay.com/content/claims/${claim.name}/${claim.claim_id}/stream.mp4`; const path = `https://api.piratebay.com/content/claims/${claim.name}/${claim.claim_id}/stream.mp4`;
const sources = [ const sources = [
{ {

View file

@ -3,6 +3,7 @@ export const CONFIRM_EXTERNAL_RESOURCE = 'confirm_external_resource';
export const INCOMPATIBLE_DAEMON = 'incompatible_daemon'; export const INCOMPATIBLE_DAEMON = 'incompatible_daemon';
export const FILE_TIMEOUT = 'file_timeout'; export const FILE_TIMEOUT = 'file_timeout';
export const DOWNLOADING = 'downloading'; export const DOWNLOADING = 'downloading';
export const AUTO_GENERATE_THUMBNAIL = 'auto_generate_thumbnail';
export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded'; export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded';
export const AUTO_UPDATE_CONFIRM = 'auto_update_confirm'; export const AUTO_UPDATE_CONFIRM = 'auto_update_confirm';
export const ERROR = 'error'; export const ERROR = 'error';

View file

@ -3,7 +3,7 @@ import y18n from 'y18n';
const i18n = y18n({ const i18n = y18n({
directory: `static/locales`.replace(/\\/g, '\\\\'), directory: `static/locales`.replace(/\\/g, '\\\\'),
updateFiles: false, updateFiles: true,
locale: 'en', locale: 'en',
}); });
// @endif // @endif

View file

@ -0,0 +1,16 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { doUploadThumbnail } from 'redux/actions/publish';
import { doToast } from 'lbry-redux';
import ModalAutoGenerateThumbnail from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()),
upload: buffer => dispatch(doUploadThumbnail(null, buffer)),
showToast: options => dispatch(doToast(options)),
});
export default connect(
null,
perform
)(ModalAutoGenerateThumbnail);

View file

@ -0,0 +1,84 @@
// @flow
import React, { useRef } from 'react';
import { Modal } from 'modal/modal';
type Props = {
upload: Buffer => void,
filePath: string,
closeModal: () => void,
showToast: ({}) => void,
};
function ModalAutoGenerateThumbnail(props: Props) {
const { closeModal, filePath, upload, showToast } = props;
const playerRef = useRef();
let src = filePath.replace(/\\/g, '/');
src = src[0] !== '/' ? `/${src}` : src;
src = encodeURI(`file://${src}`).replace(/[?#]/g, encodeURIComponent);
function uploadImage() {
const imageBuffer = captureSnapshot();
if (imageBuffer) {
upload(imageBuffer);
closeModal();
} else {
onError();
}
}
function captureSnapshot(): ?Buffer {
const player = playerRef.current;
if (!player) {
return;
}
const canvas = document.createElement('canvas');
canvas.width = player.videoWidth;
canvas.height = player.videoHeight;
const context = canvas.getContext('2d');
context.drawImage(player, 0, 0, canvas.width, canvas.height);
const dataURL = canvas.toDataURL();
const rawData = dataURL.replace(/data:image\/\w+;base64,/i, '');
canvas.remove();
return Buffer.from(rawData, 'base64');
}
function resize(): void {
const player = playerRef.current;
if (!player) {
return;
}
console.log('resized');
const fixedWidth = 450;
const videoWidth = player.videoWidth;
const videoHeight = player.videoHeight;
player.width = fixedWidth;
player.height = Math.floor(videoHeight * (fixedWidth / videoWidth));
}
function onError(): void {
showToast({ isError: true, message: __("Something didn't work. Please try again.") });
}
return (
<Modal
isOpen
title={__('Upload Thumbnail')}
contentLabel={__('Confirm Thumbnail Upload')}
type="confirm"
confirmButtonLabel={__('Upload')}
onConfirmed={uploadImage}
onAborted={closeModal}
>
<section className="card__content">
<p className="card__subtitle">{__('Pause at any time to select a thumbnail from your video')}.</p>
<video ref={playerRef} src={src} onLoadedMetadata={resize} onError={onError} controls />
</section>
</Modal>
);
}
export default ModalAutoGenerateThumbnail;

View file

@ -4,6 +4,7 @@ import * as MODALS from 'constants/modal_types';
import ModalError from 'modal/modalError'; import ModalError from 'modal/modalError';
import ModalAuthFailure from 'modal/modalAuthFailure'; import ModalAuthFailure from 'modal/modalAuthFailure';
import ModalDownloading from 'modal/modalDownloading'; import ModalDownloading from 'modal/modalDownloading';
import ModalAutoGenerateThumbnail from 'modal/modalAutoGenerateThumbnail';
import ModalAutoUpdateDownloaded from 'modal/modalAutoUpdateDownloaded'; import ModalAutoUpdateDownloaded from 'modal/modalAutoUpdateDownloaded';
import ModalAutoUpdateConfirm from 'modal/modalAutoUpdateConfirm'; import ModalAutoUpdateConfirm from 'modal/modalAutoUpdateConfirm';
import ModalUpgrade from 'modal/modalUpgrade'; import ModalUpgrade from 'modal/modalUpgrade';
@ -51,6 +52,8 @@ function ModalRouter(props: Props) {
return <ModalUpgrade {...modalProps} />; return <ModalUpgrade {...modalProps} />;
case MODALS.DOWNLOADING: case MODALS.DOWNLOADING:
return <ModalDownloading {...modalProps} />; return <ModalDownloading {...modalProps} />;
case MODALS.AUTO_GENERATE_THUMBNAIL:
return <ModalAutoGenerateThumbnail {...modalProps} />;
case MODALS.AUTO_UPDATE_DOWNLOADED: case MODALS.AUTO_UPDATE_DOWNLOADED:
return <ModalAutoUpdateDownloaded {...modalProps} />; return <ModalAutoUpdateDownloaded {...modalProps} />;
case MODALS.AUTO_UPDATE_CONFIRM: case MODALS.AUTO_UPDATE_CONFIRM:

View file

@ -68,10 +68,22 @@ export const doUpdatePublishForm = (publishFormValue: UpdatePublishFormData) =>
data: { ...publishFormValue }, data: { ...publishFormValue },
}); });
export const doUploadThumbnail = (filePath: string) => (dispatch: Dispatch) => { export const doUploadThumbnail = (filePath: string, thumbnailBuffer: Uint8Array) => (dispatch: Dispatch) => {
const thumbnail = fs.readFileSync(filePath); let thumbnail, fileExt, fileName, fileType;
const fileExt = path.extname(filePath);
const fileName = path.basename(filePath); if (filePath) {
thumbnail = fs.readFileSync(filePath);
fileExt = path.extname(filePath);
fileName = path.basename(filePath);
fileType = `image/${fileExt.slice(1)}`;
} else if (thumbnailBuffer) {
thumbnail = thumbnailBuffer;
fileExt = '.png';
fileName = 'thumbnail.png';
fileType = 'image/png';
} else {
return null;
}
const makeid = () => { const makeid = () => {
let text = ''; let text = '';
@ -102,7 +114,7 @@ export const doUploadThumbnail = (filePath: string) => (dispatch: Dispatch) => {
const data = new FormData(); const data = new FormData();
const name = makeid(); const name = makeid();
const file = new File([thumbnail], fileName, { type: `image/${fileExt.slice(1)}` }); const file = new File([thumbnail], fileName, { type: fileType });
data.append('name', name); data.append('name', name);
data.append('file', file); data.append('file', file);

2369
yarn.lock

File diff suppressed because it is too large Load diff