diff --git a/babel.config.js b/babel.config.js index 659c0d744..5697c999a 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,7 +4,6 @@ module.exports = api => { return { presets: ['@babel/env', '@babel/react', '@babel/flow'], plugins: [ - '@babel/plugin-syntax-dynamic-import', 'import-glob', '@babel/plugin-transform-runtime', ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], diff --git a/static/app-strings.json b/static/app-strings.json index fac2a112c..836d74cfe 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -903,4 +903,4 @@ "Reach out to hello@lbry.com for help, or check out %help_link%.": "Reach out to hello@lbry.com for help, or check out %help_link%.", "You're not following any tags. Smash that %customize% button!": "You're not following any tags. Smash that %customize% button!", "customize": "customize" -} \ No newline at end of file +} diff --git a/ui/component/fileRender/view.jsx b/ui/component/fileRender/view.jsx index a87757b27..9f8557e7a 100644 --- a/ui/component/fileRender/view.jsx +++ b/ui/component/fileRender/view.jsx @@ -16,11 +16,11 @@ import path from 'path'; import fs from 'fs'; import Yrbl from 'component/yrbl'; -// @if TARGET='app' import DocumentViewer from 'component/viewers/documentViewer'; -import DocxViewer from 'component/viewers/docxViewer'; -import HtmlViewer from 'component/viewers/htmlViewer'; import PdfViewer from 'component/viewers/pdfViewer'; +import HtmlViewer from 'component/viewers/htmlViewer'; +// @if TARGET='app' +import DocxViewer from 'component/viewers/docxViewer'; import ComicBookViewer from 'component/viewers/comicBookViewer'; import ThreeViewer from 'component/viewers/threeViewer'; // @endif @@ -102,26 +102,33 @@ class FileRender extends React.PureComponent { // Add routes to viewer... }; + // Supported contentTypes + const contentTypes = { + 'application/pdf': , + 'text/html': , + 'text/htm': , + }; + // Supported fileType const fileTypes = { // @if TARGET='app' - pdf: , docx: , - html: , - htm: , // @endif // Add routes to viewer... }; - // Check for a valid fileType or mediaType - let viewer = (fileType && fileTypes[fileType]) || mediaTypes[mediaType]; + // Check for a valid fileType, mediaType, or contentType + let viewer = (fileType && fileTypes[fileType]) || mediaTypes[mediaType] || contentTypes[contentType]; // Check for Human-readable files if (!viewer && readableFiles.includes(mediaType)) { viewer = ( fs.createReadStream(downloadPath, options), + // @if TARGET='app' + file: options => fs.createReadStream(downloadPath, options), + // @endif + stream: source, fileType, contentType, }} diff --git a/ui/component/fileViewer/index.js b/ui/component/fileViewer/index.js index 3dce437cc..8e7f5db1f 100644 --- a/ui/component/fileViewer/index.js +++ b/ui/component/fileViewer/index.js @@ -5,6 +5,7 @@ import { makeSelectThumbnailForUri, makeSelectStreamingUrlForUri, makeSelectMediaTypeForUri, + makeSelectContentTypeForUri, makeSelectUriIsStreamable, makeSelectTitleForUri, } from 'lbry-redux'; @@ -23,6 +24,7 @@ const select = (state, props) => { title: makeSelectTitleForUri(uri)(state), thumbnail: makeSelectThumbnailForUri(uri)(state), mediaType: makeSelectMediaTypeForUri(uri)(state), + contentType: makeSelectContentTypeForUri(uri)(state), fileInfo: makeSelectFileInfoForUri(uri)(state), obscurePreview: makeSelectShouldObscurePreview(uri)(state), isPlaying: makeSelectIsPlaying(uri)(state), diff --git a/ui/component/fileViewer/view.jsx b/ui/component/fileViewer/view.jsx index 8fc1b0a3d..c34372c74 100644 --- a/ui/component/fileViewer/view.jsx +++ b/ui/component/fileViewer/view.jsx @@ -15,6 +15,7 @@ import { onFullscreenChange } from 'util/full-screen'; type Props = { mediaType: string, + contentType: string, isLoading: boolean, isPlaying: boolean, fileInfo: FileListItem, @@ -47,6 +48,7 @@ export default function FileViewer(props: Props) { triggerAnalyticsView, claimRewards, mediaType, + contentType, } = props; const [playTime, setPlayTime] = useState(); const [fileViewerRect, setFileViewerRect] = usePersistedState('inline-file-viewer:rect'); @@ -56,7 +58,9 @@ export default function FileViewer(props: Props) { }); const inline = pageUri === uri; - const isReadyToPlay = (IS_WEB && isStreamable) || (isStreamable && streamingUrl) || (fileInfo && fileInfo.completed); + const webStreamOnly = contentType === 'application/pdf' || mediaType === 'text'; + const isReadyToPlay = + (IS_WEB && (isStreamable || webStreamOnly)) || (isStreamable && streamingUrl) || (fileInfo && fileInfo.completed); const loadingMessage = !isStreamable && fileInfo && fileInfo.blobs_completed >= 1 && (!fileInfo.download_path || !fileInfo.written_bytes) ? __("It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds.") diff --git a/ui/component/fileViewerInitiator/index.js b/ui/component/fileViewerInitiator/index.js index e3d235382..a0f91605b 100644 --- a/ui/component/fileViewerInitiator/index.js +++ b/ui/component/fileViewerInitiator/index.js @@ -6,6 +6,7 @@ import { makeSelectThumbnailForUri, makeSelectStreamingUrlForUri, makeSelectMediaTypeForUri, + makeSelectContentTypeForUri, makeSelectUriIsStreamable, } from 'lbry-redux'; import { makeSelectCostInfoForUri } from 'lbryinc'; @@ -16,6 +17,7 @@ import FileViewer from './view'; const select = (state, props) => ({ thumbnail: makeSelectThumbnailForUri(props.uri)(state), mediaType: makeSelectMediaTypeForUri(props.uri)(state), + contentType: makeSelectContentTypeForUri(props.uri)(state), fileInfo: makeSelectFileInfoForUri(props.uri)(state), obscurePreview: makeSelectShouldObscurePreview(props.uri)(state), isPlaying: makeSelectIsPlaying(props.uri)(state), diff --git a/ui/component/fileViewerInitiator/view.jsx b/ui/component/fileViewerInitiator/view.jsx index 887266213..856a34ad7 100644 --- a/ui/component/fileViewerInitiator/view.jsx +++ b/ui/component/fileViewerInitiator/view.jsx @@ -14,6 +14,7 @@ const SPACE_BAR_KEYCODE = 32; type Props = { play: string => void, mediaType: string, + contentType: string, isLoading: boolean, isPlaying: boolean, fileInfo: FileListItem, @@ -31,6 +32,7 @@ export default function FileViewer(props: Props) { const { play, mediaType, + contentType, isPlaying, fileInfo, uri, @@ -45,7 +47,8 @@ export default function FileViewer(props: Props) { const cost = costInfo && costInfo.cost; const isPlayable = ['audio', 'video'].includes(mediaType); const fileStatus = fileInfo && fileInfo.status; - const supported = (IS_WEB && isStreamable) || !IS_WEB; + const webStreamOnly = contentType === 'application/pdf' || mediaType === 'text'; + const supported = (IS_WEB && (isStreamable || webStreamOnly)) || !IS_WEB; // Wrap this in useCallback because we need to use it to the keyboard effect // If we don't a new instance will be created for every render and react will think the dependencies have changed, which will add/remove the listener for every render diff --git a/ui/component/viewers/documentViewer.jsx b/ui/component/viewers/documentViewer.jsx index 26162edfc..ec73059e5 100644 --- a/ui/component/viewers/documentViewer.jsx +++ b/ui/component/viewers/documentViewer.jsx @@ -1,14 +1,16 @@ // @flow -import React, { Suspense } from 'react'; +import React from 'react'; import LoadingScreen from 'component/common/loading-screen'; import MarkdownPreview from 'component/common/markdown-preview'; import CodeViewer from 'component/viewers/codeViewer'; +import * as https from 'https'; type Props = { theme: string, source: { - stream: string => any, + file: (?string) => any, + stream: string, fileType: string, contentType: string, }, @@ -32,9 +34,9 @@ class DocumentViewer extends React.PureComponent { componentDidMount() { const { source } = this.props; - - if (source && source.stream) { - const stream = source.stream('utf8'); + // @if TARGET='app' + if (source && source.file) { + const stream = source.file('utf8'); let data = ''; @@ -50,6 +52,32 @@ class DocumentViewer extends React.PureComponent { this.setState({ error: true, loading: false }); }); } + // @endif + // @if TARGET='web' + if (source && source.stream) { + https.get( + source.stream, + function(response) { + if (response.statusCode === 200) { + let body = ''; + let i = 0; + response.on('data', function(chunk) { + i = i + 1; + body += chunk; + }); + response.on( + 'end', + function() { + this.setState({ content: body, loading: false }); + }.bind(this) + ); + } else { + this.setState({ error: true, loading: false }); + } + }.bind(this) + ); + } + // @endif } renderDocument() { @@ -58,8 +86,7 @@ class DocumentViewer extends React.PureComponent { const { source, theme } = this.props; const { fileType, contentType } = source; const markdownType = ['md', 'markdown']; - - if (markdownType.includes(fileType)) { + if (markdownType.includes(fileType) || contentType === 'text/markdown' || contentType === 'text/md') { // Render markdown viewer = ; } else { diff --git a/ui/component/viewers/htmlViewer.jsx b/ui/component/viewers/htmlViewer.jsx index f3048c553..2ea30d75d 100644 --- a/ui/component/viewers/htmlViewer.jsx +++ b/ui/component/viewers/htmlViewer.jsx @@ -11,7 +11,12 @@ class HtmlViewer extends React.PureComponent { const { source } = this.props; return (
+ {/* @if TARGET='app' */}