mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-08-23 17:47:24 +00:00
improve and optimize renderFile method (fileSource)
This commit is contained in:
parent
2109685d5a
commit
2c8f11750a
7 changed files with 60 additions and 70 deletions
|
@ -9,33 +9,36 @@ import DocxViewer from 'component/viewers/docxViewer';
|
||||||
type Props = {
|
type Props = {
|
||||||
mediaType: string,
|
mediaType: string,
|
||||||
source: {
|
source: {
|
||||||
filePath: string,
|
fileName: string,
|
||||||
fileType: string,
|
fileType: string,
|
||||||
downloadPath: string,
|
downloadPath: string,
|
||||||
|
stream: opts => void,
|
||||||
|
blob: callback => void,
|
||||||
},
|
},
|
||||||
currentTheme: string,
|
currentTheme: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileRender extends React.PureComponent<Props> {
|
class FileRender extends React.PureComponent<Props> {
|
||||||
renderViewer() {
|
renderViewer() {
|
||||||
const { source, mediaType, currentTheme: theme } = this.props;
|
const { source, mediaType, currentTheme } = this.props;
|
||||||
const viewerProps = { source, theme };
|
|
||||||
|
// Extract relevant data to render file
|
||||||
|
const { blob, stream, fileName, fileType, contentType, downloadPath } = source;
|
||||||
|
|
||||||
// Supported mediaTypes
|
// Supported mediaTypes
|
||||||
const mediaTypes = {
|
const mediaTypes = {
|
||||||
'3D-file': <ThreeViewer {...viewerProps} />,
|
'3D-file': <ThreeViewer source={{ fileType, downloadPath }} theme={currentTheme} />,
|
||||||
document: <DocumentViewer {...viewerProps} />,
|
document: <DocumentViewer source={{ stream, fileType, contentType }} theme={currentTheme} />,
|
||||||
// Add routes to viewer...
|
// Add routes to viewer...
|
||||||
};
|
};
|
||||||
|
|
||||||
// Supported fileType
|
// Supported fileType
|
||||||
const fileTypes = {
|
const fileTypes = {
|
||||||
pdf: <PdfViewer {...viewerProps} />,
|
pdf: <PdfViewer source={downloadPath} />,
|
||||||
docx: <DocxViewer {...viewerProps} />,
|
docx: <DocxViewer source={downloadPath} />,
|
||||||
// Add routes to viewer...
|
// Add routes to viewer...
|
||||||
};
|
};
|
||||||
|
|
||||||
const { fileType } = source;
|
|
||||||
const viewer = mediaType && source && (fileTypes[fileType] || mediaTypes[mediaType]);
|
const viewer = mediaType && source && (fileTypes[fileType] || mediaTypes[mediaType]);
|
||||||
const unsupportedMessage = __("Sorry, looks like we can't preview this file.");
|
const unsupportedMessage = __("Sorry, looks like we can't preview this file.");
|
||||||
const unsupported = <LoadingScreen status={unsupportedMessage} spinner={false} />;
|
const unsupported = <LoadingScreen status={unsupportedMessage} spinner={false} />;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import FileRender from 'component/fileRender';
|
||||||
import Thumbnail from 'component/common/thumbnail';
|
import Thumbnail from 'component/common/thumbnail';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
|
||||||
class VideoPlayer extends React.PureComponent {
|
class MediaPlayer extends React.PureComponent {
|
||||||
static MP3_CONTENT_TYPES = ['audio/mpeg3', 'audio/mpeg'];
|
static MP3_CONTENT_TYPES = ['audio/mpeg3', 'audio/mpeg'];
|
||||||
static FILE_MEDIA_TYPES = ['e-book', 'comic-book', 'document', '3D-file'];
|
static FILE_MEDIA_TYPES = ['e-book', 'comic-book', 'document', '3D-file'];
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class VideoPlayer extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
// use renderAudio override for mp3
|
// use renderAudio override for mp3
|
||||||
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
||||||
this.renderAudio(container, null, false);
|
this.renderAudio(container, null, false);
|
||||||
}
|
}
|
||||||
// Render custom viewer: FileRender
|
// Render custom viewer: FileRender
|
||||||
|
@ -105,7 +105,7 @@ class VideoPlayer extends React.PureComponent {
|
||||||
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
||||||
const container = this.media.children[0];
|
const container = this.media.children[0];
|
||||||
|
|
||||||
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
||||||
this.renderAudio(this.media, true);
|
this.renderAudio(this.media, true);
|
||||||
} else {
|
} else {
|
||||||
player.render(this.file(), container, {
|
player.render(this.file(), container, {
|
||||||
|
@ -183,30 +183,30 @@ class VideoPlayer extends React.PureComponent {
|
||||||
// This files are supported using a custom viewer
|
// This files are supported using a custom viewer
|
||||||
const { mediaType } = this.props;
|
const { mediaType } = this.props;
|
||||||
|
|
||||||
return VideoPlayer.FILE_MEDIA_TYPES.indexOf(mediaType) > -1;
|
return MediaPlayer.FILE_MEDIA_TYPES.indexOf(mediaType) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFile() {
|
renderFile() {
|
||||||
// This is what render-media does with unplayable files
|
// This is what render-media does with unplayable files
|
||||||
const { fileName, downloadPath, contentType, mediaType } = this.props;
|
const { fileName, downloadPath, contentType, mediaType } = this.props;
|
||||||
|
|
||||||
toBlobURL(fs.createReadStream(downloadPath), contentType, (err, url) => {
|
|
||||||
if (err) {
|
|
||||||
this.setState({ unsupported: true });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// File to render
|
// File to render
|
||||||
const fileSource = {
|
const fileSource = {
|
||||||
fileName,
|
fileName,
|
||||||
contentType,
|
contentType,
|
||||||
downloadPath,
|
downloadPath,
|
||||||
filePath: url,
|
|
||||||
fileType: path.extname(fileName).substring(1),
|
fileType: path.extname(fileName).substring(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Readable stream from file
|
||||||
|
fileSource.stream = opts => fs.createReadStream(downloadPath, opts);
|
||||||
|
|
||||||
|
// Blob url from stream
|
||||||
|
fileSource.blob = callback =>
|
||||||
|
toBlobURL(fs.createReadStream(downloadPath), contentType, callback);
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
this.setState({ fileSource });
|
this.setState({ fileSource });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAudio(container, autoplay) {
|
renderAudio(container, autoplay) {
|
||||||
|
@ -287,5 +287,5 @@ class VideoPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VideoPlayer;
|
export default MediaPlayer;
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import fs from 'fs';
|
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
import CodeViewer from 'component/viewers/codeViewer';
|
import CodeViewer from 'component/viewers/codeViewer';
|
||||||
import MarkdownPreview from 'component/common/markdown-preview';
|
import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
|
@ -9,9 +8,9 @@ import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
type Props = {
|
type Props = {
|
||||||
theme: string,
|
theme: string,
|
||||||
source: {
|
source: {
|
||||||
|
stream: opts => void,
|
||||||
fileType: string,
|
fileType: string,
|
||||||
filePath: string,
|
contentType: string,
|
||||||
downloadPath: string,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ class DocumentViewer extends React.PureComponent<Props> {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { source } = this.props;
|
const { source } = this.props;
|
||||||
const stream = fs.createReadStream(source.downloadPath, 'utf8');
|
const stream = source.stream('utf8');
|
||||||
|
|
||||||
let data = '';
|
let data = '';
|
||||||
|
|
||||||
|
@ -40,23 +39,20 @@ class DocumentViewer extends React.PureComponent<Props> {
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('error', error => {
|
stream.on('error', error => {
|
||||||
this.setState({ error });
|
this.setState({ error: true, loading: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDocument() {
|
renderDocument(content = null) {
|
||||||
let viewer = null;
|
let viewer = null;
|
||||||
const { source, theme } = this.props;
|
const { source, theme } = this.props;
|
||||||
const { fileType, contentType } = source;
|
const { fileType, contentType } = source;
|
||||||
const { content, error } = this.state;
|
|
||||||
|
|
||||||
const isReady = content && !error;
|
|
||||||
const markdownType = ['md', 'markdown'];
|
const markdownType = ['md', 'markdown'];
|
||||||
|
|
||||||
if (isReady && markdownType.includes(fileType)) {
|
if (markdownType.includes(fileType)) {
|
||||||
// Render markdown
|
// Render markdown
|
||||||
viewer = <MarkdownPreview content={content} promptLinks />;
|
viewer = <MarkdownPreview content={content} promptLinks />;
|
||||||
} else if (isReady) {
|
} else {
|
||||||
// Render plain text
|
// Render plain text
|
||||||
viewer = <CodeViewer value={content} contentType={contentType} theme={theme} />;
|
viewer = <CodeViewer value={content} contentType={contentType} theme={theme} />;
|
||||||
}
|
}
|
||||||
|
@ -65,15 +61,16 @@ class DocumentViewer extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { error, loading } = this.state;
|
const { error, loading, content } = this.state;
|
||||||
|
const isReady = content && !error;
|
||||||
const loadingMessage = __('Rendering document.');
|
const loadingMessage = __('Rendering document.');
|
||||||
const errorMessage = __("Sorry, looks like we can't load the document.");
|
const errorMessage = __("Sorry, looks like we can't load the document.");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="file-render__viewer document-viewer">
|
<div className="file-render__viewer document-viewer">
|
||||||
{loading && !error && <LoadingScreen status={loadingMessage} spinner />}
|
{loading && !error && <LoadingScreen status={loadingMessage} spinner />}
|
||||||
{error && <LoadingScreen status={errorMessage} spinner={false} />}
|
{error && <LoadingScreen status={errorMessage} spinner={!error} />}
|
||||||
{this.renderDocument()}
|
{isReady && this.renderDocument(content)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,7 @@ import LoadingScreen from 'component/common/loading-screen';
|
||||||
import MarkdownPreview from 'component/common/markdown-preview';
|
import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
source: {
|
source: string,
|
||||||
fileType: string,
|
|
||||||
filePath: string,
|
|
||||||
downloadPath: string,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DocxViewer extends React.PureComponent<Props> {
|
class DocxViewer extends React.PureComponent<Props> {
|
||||||
|
@ -26,6 +22,7 @@ class DocxViewer extends React.PureComponent<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { source } = this.props;
|
const { source } = this.props;
|
||||||
|
|
||||||
|
// Overwrite element and styles
|
||||||
const options = {
|
const options = {
|
||||||
styleMap: [
|
styleMap: [
|
||||||
"p[style-name='Title'] => h1:fresh",
|
"p[style-name='Title'] => h1:fresh",
|
||||||
|
@ -38,15 +35,19 @@ class DocxViewer extends React.PureComponent<Props> {
|
||||||
"p[style-name='Aside Text'] => div.aside > p:fresh",
|
"p[style-name='Aside Text'] => div.aside > p:fresh",
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Parse docx to html
|
||||||
mammoth
|
mammoth
|
||||||
.convertToHtml({ path: source.downloadPath }, options)
|
.convertToHtml({ path: source }, options)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
|
// Remove images and tables
|
||||||
const breakdance = new Breakdance({ omit: ['table', 'img'] });
|
const breakdance = new Breakdance({ omit: ['table', 'img'] });
|
||||||
|
// Convert html to markdown
|
||||||
const markdown = breakdance.render(result.value);
|
const markdown = breakdance.render(result.value);
|
||||||
this.setState({ content: markdown, loading: false });
|
this.setState({ content: markdown, loading: false });
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setState({ error, loading: false });
|
this.setState({ error: true, loading: false });
|
||||||
})
|
})
|
||||||
.done();
|
.done();
|
||||||
}
|
}
|
||||||
|
@ -54,11 +55,12 @@ class DocxViewer extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { content, error, loading } = this.state;
|
const { content, error, loading } = this.state;
|
||||||
const loadingMessage = __('Rendering document.');
|
const loadingMessage = __('Rendering document.');
|
||||||
|
const errorMessage = __("Sorry, looks like we can't load the document.");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="document-viewer file-render__viewer">
|
<div className="document-viewer file-render__viewer">
|
||||||
{loading && <LoadingScreen status={loadingMessage} spinner />}
|
{loading && <LoadingScreen status={loadingMessage} spinner />}
|
||||||
{error && <LoadingScreen status={error} spinner={false} />}
|
{error && <LoadingScreen status={errorMessage} spinner={false} />}
|
||||||
{content && (
|
{content && (
|
||||||
<div className="document-viewer__content">
|
<div className="document-viewer__content">
|
||||||
<MarkdownPreview content={content} promptLinks />
|
<MarkdownPreview content={content} promptLinks />
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { stopContextMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
source: {
|
source: string,
|
||||||
fileType: string,
|
|
||||||
filePath: string,
|
|
||||||
downloadPath: string,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PdfViewer extends React.PureComponent<Props> {
|
class PdfViewer extends React.PureComponent<Props> {
|
||||||
|
@ -15,20 +12,11 @@ class PdfViewer extends React.PureComponent<Props> {
|
||||||
this.viewer = React.createRef();
|
this.viewer = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Enable context-menu
|
|
||||||
stopContextMenu = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { source } = this.props;
|
const { source } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="file-render__viewer" onContextMenu={this.stopContextMenu}>
|
<div className="file-render__viewer" onContextMenu={stopContextMenu}>
|
||||||
<webview
|
<webview ref={this.viewer} src={`chrome://pdf-viewer/index.html?src=file://${source}`} />
|
||||||
ref={this.viewer}
|
|
||||||
src={`chrome://pdf-viewer/index.html?src=file://${source.downloadPath}`}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ type Props = {
|
||||||
autoRotate: boolean,
|
autoRotate: boolean,
|
||||||
source: {
|
source: {
|
||||||
fileType: string,
|
fileType: string,
|
||||||
filePath: string,
|
downloadPath: string,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,13 @@ const Loader = (fileType, manager) => {
|
||||||
return fileTypes[fileType] ? fileTypes[fileType]() : null;
|
return fileTypes[fileType] ? fileTypes[fileType]() : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ThreeLoader = ({ fileType, filePath }, renderModel, managerEvents) => {
|
const ThreeLoader = ({ fileType = null, downloadPath = null }, renderModel, managerEvents) => {
|
||||||
if (fileType) {
|
if (fileType) {
|
||||||
const manager = Manager(managerEvents);
|
const manager = Manager(managerEvents);
|
||||||
const loader = Loader(fileType, manager);
|
const loader = Loader(fileType, manager);
|
||||||
|
|
||||||
if (loader) {
|
if (loader) {
|
||||||
loader.load(filePath, data => {
|
loader.load(`file://${downloadPath}`, data => {
|
||||||
renderModel(fileType, data);
|
renderModel(fileType, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue