From faf44023091c7a4d38c03076360ed348ea5b3522 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Fri, 2 Aug 2019 02:21:28 -0400 Subject: [PATCH] working? --- dist/bundle.es.js | 94 ++++++++++++++++++++++++-------- dist/flow-typed/Lbry.js | 2 +- flow-typed/Lbry.js | 2 +- package.json | 1 + src/index.js | 4 ++ src/lbry.js | 47 ++++++++++------ src/redux/actions/file.js | 27 +++++++-- src/redux/selectors/file.js | 9 ++- src/redux/selectors/file_info.js | 42 +++++++++++++- yarn.lock | 5 ++ 10 files changed, 181 insertions(+), 52 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index c138c15..2177543 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } require('proxy-polyfill'); +var mime = _interopDefault(require('mime')); var reselect = require('reselect'); var uuid = _interopDefault(require('uuid/v4')); var fs = _interopDefault(require('fs')); @@ -696,23 +697,30 @@ const Lbry = { }, // Returns a human readable media type based on the content type or extension of a file that is returned by the sdk - getMediaType: (contentType, extname) => { - if (extname) { - const formats = [[/^(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], [/^(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], [/^(html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org)$/i, 'document'], [/^(stl|obj|fbx|gcode)$/i, '3D-file']]; + getMediaType: (contentType, fileName) => { + const formats = [[/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], [/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], [/\.(h|go|ja|java|js|jsx|c|cpp|cs|css|rb|scss|sh|php|py)$/i, 'script'], [/\.(json|csv|txt|log|md|markdown|docx|pdf|xml|yml|yaml)$/i, 'document'], [/\.(pdf|odf|doc|docx|epub|org|rtf)$/i, 'e-book'], [/\.(stl|obj|fbx|gcode)$/i, '3D-file'], [/\.(cbr|cbt|cbz)$/i, 'comic-book']]; + + const extName = mime.getExtension(contentType); + const fileExt = extName ? `.${extName}` : null; + const testString = fileName || fileExt; + + // Get mediaType from file extension + if (testString) { const res = formats.reduce((ret, testpair) => { - switch (testpair[0].test(ret)) { - case true: - return testpair[1]; - default: - return ret; - } - }, extname); - return res === extname ? 'unknown' : res; - } else if (contentType) { - // $FlowFixMe + const [regex, mediaType] = testpair; + + return regex.test(ret) ? mediaType : ret; + }, testString); + + if (res !== testString) return res; + } + + // Get mediaType from contentType + if (contentType) { return (/^[^/]+/.exec(contentType)[0] ); } + return 'unknown'; }, @@ -2447,7 +2455,7 @@ const makeSelectLoadingForUri = uri => reselect.createSelector(selectUrisLoading const selectFileInfosDownloaded = reselect.createSelector(selectFileInfosByOutpoint, selectMyClaims, (byOutpoint, myClaims) => Object.values(byOutpoint).filter(fileInfo => { const myClaimIds = myClaims.map(claim => claim.claim_id); - return fileInfo && myClaimIds.indexOf(fileInfo.claim_id) === -1 && (fileInfo.completed || fileInfo.written_bytes); + return fileInfo && myClaimIds.indexOf(fileInfo.claim_id) === -1 && (fileInfo.completed || fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0); })); // export const selectFileInfoForUri = (state, props) => { @@ -2586,6 +2594,27 @@ const selectDownloadedUris = reselect.createSelector(selectFileInfosDownloaded, // We should use permament_url but it doesn't exist in file_list info => info.slice().reverse().map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`)); +const makeSelectMediaTypeForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), makeSelectContentTypeForUri(uri), (fileInfo, contentType) => { + if (!fileInfo && !contentType) { + return undefined; + } + + const fileName = fileInfo && fileInfo.file_name; + return lbryProxy.getMediaType(contentType, fileName); +}); + +const makeSelectUriIsStreamable = uri => reselect.createSelector(makeSelectMediaTypeForUri(uri), mediaType => { + const isStreamable = ['audio', 'video', 'image'].indexOf(mediaType) !== -1; + return isStreamable; +}); + +const makeSelectDownloadPathForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { + return fileInfo && fileInfo.download_path; +}); +const makeSelectFileNameForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { + return fileInfo && fileInfo.file_name; +}); + // const selectState$4 = state => state.file || {}; @@ -2600,11 +2629,13 @@ const selectPurchasedStreamingUrls = reselect.createSelector(selectState$4, stat const selectLastPurchasedUri = reselect.createSelector(selectState$4, state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null); -const makeSelectStreamingUrlForUri = uri => reselect.createSelector(selectPurchasedStreamingUrls, streamingUrls => streamingUrls && streamingUrls[uri]); +const makeSelectStreamingUrlForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { + return fileInfo && fileInfo.streaming_url; +}); // -function doFileGet(uri, saveFile = true) { +function doFileGet(uri, saveFile = true, onSuccess) { return dispatch => { dispatch({ type: LOADING_FILE_STARTED, @@ -2615,7 +2646,7 @@ function doFileGet(uri, saveFile = true) { // set save_file argument to True to save the file (old behaviour) lbryProxy.get({ uri, save_file: saveFile }).then(streamInfo => { - const timeout = streamInfo === null || typeof streamInfo !== 'object'; + const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; if (timeout) { dispatch({ @@ -2633,8 +2664,19 @@ function doFileGet(uri, saveFile = true) { const { streaming_url: streamingUrl } = streamInfo; dispatch({ type: PURCHASE_URI_COMPLETED, - data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null } + data: { uri, streamingUrl } }); + dispatch({ + type: FETCH_FILE_INFO_COMPLETED, + data: { + fileInfo: streamInfo, + outpoint: streamInfo.outpoint + } + }); + + if (onSuccess) { + onSuccess(streamInfo); + } } }).catch(() => { dispatch({ @@ -2647,14 +2689,14 @@ function doFileGet(uri, saveFile = true) { }); dispatch(doToast({ - message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, + message: `Failed to view ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, isError: true })); }); }; } -function doPurchaseUri(uri, costInfo, saveFile = true) { +function doPurchaseUri(uri, costInfo, saveFile = true, onSuccess) { return (dispatch, getState) => { dispatch({ type: PURCHASE_URI_STARTED, @@ -2685,7 +2727,7 @@ function doPurchaseUri(uri, costInfo, saveFile = true) { return; } - dispatch(doFileGet(uri, saveFile)); + dispatch(doFileGet(uri, saveFile, onSuccess)); }; } @@ -3921,13 +3963,15 @@ reducers$2[DOWNLOADING_PROGRESSED] = (state, action) => { }; reducers$2[DOWNLOADING_CANCELED] = (state, action) => { - const { outpoint } = action.data; + const { uri, outpoint } = action.data; const newDownloading = Object.assign({}, state.downloadingByOutpoint); delete newDownloading[outpoint]; + delete newLoading[uri]; return Object.assign({}, state, { - downloadingByOutpoint: newDownloading + downloadingByOutpoint: newDownloading, + urisLoading: newLoading }); }; @@ -4842,12 +4886,15 @@ exports.makeSelectContentPositionForUri = makeSelectContentPositionForUri; exports.makeSelectContentTypeForUri = makeSelectContentTypeForUri; exports.makeSelectCoverForUri = makeSelectCoverForUri; exports.makeSelectDateForUri = makeSelectDateForUri; +exports.makeSelectDownloadPathForUri = makeSelectDownloadPathForUri; exports.makeSelectDownloadingForUri = makeSelectDownloadingForUri; exports.makeSelectFetchingChannelClaims = makeSelectFetchingChannelClaims; exports.makeSelectFileInfoForUri = makeSelectFileInfoForUri; +exports.makeSelectFileNameForUri = makeSelectFileNameForUri; exports.makeSelectFirstRecommendedFileForUri = makeSelectFirstRecommendedFileForUri; exports.makeSelectIsUriResolving = makeSelectIsUriResolving; exports.makeSelectLoadingForUri = makeSelectLoadingForUri; +exports.makeSelectMediaTypeForUri = makeSelectMediaTypeForUri; exports.makeSelectMetadataForUri = makeSelectMetadataForUri; exports.makeSelectMetadataItemForUri = makeSelectMetadataItemForUri; exports.makeSelectNsfwCountForChannel = makeSelectNsfwCountForChannel; @@ -4864,6 +4911,7 @@ exports.makeSelectThumbnailForUri = makeSelectThumbnailForUri; exports.makeSelectTitleForUri = makeSelectTitleForUri; exports.makeSelectTotalItemsForChannel = makeSelectTotalItemsForChannel; exports.makeSelectTotalPagesForChannel = makeSelectTotalPagesForChannel; +exports.makeSelectUriIsStreamable = makeSelectUriIsStreamable; exports.normalizeURI = normalizeURI; exports.notificationsReducer = notificationsReducer; exports.parseQueryParams = parseQueryParams; diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index 335eda1..a403ffb 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -68,7 +68,7 @@ declare type ResolveResponse = { [string]: Claim | { error?: {} }, }; -declare type GetResponse = FileListItem; +declare type GetResponse = FileListItem & { error?: string }; declare type GenericTxResponse = { height: number, diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index 335eda1..a403ffb 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -68,7 +68,7 @@ declare type ResolveResponse = { [string]: Claim | { error?: {} }, }; -declare type GetResponse = FileListItem; +declare type GetResponse = FileListItem & { error?: string }; declare type GenericTxResponse = { height: number, diff --git a/package.json b/package.json index 21b595f..8cba56d 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "format": "prettier 'src/**/*.{js,json}' --write" }, "dependencies": { + "mime": "^2.4.4", "proxy-polyfill": "0.1.6", "reselect": "^3.0.0", "uuid": "^3.3.2" diff --git a/src/index.js b/src/index.js index 2f93891..9a5574e 100644 --- a/src/index.js +++ b/src/index.js @@ -217,6 +217,10 @@ export { selectFileListDownloadedSort, selectFileListPublishedSort, selectDownloadedUris, + makeSelectMediaTypeForUri, + makeSelectUriIsStreamable, + makeSelectDownloadPathForUri, + makeSelectFileNameForUri, } from 'redux/selectors/file_info'; export { diff --git a/src/lbry.js b/src/lbry.js index 07fe1f0..5ceb6dd 100644 --- a/src/lbry.js +++ b/src/lbry.js @@ -1,5 +1,6 @@ // @flow import 'proxy-polyfill'; +import mime from 'mime'; const CHECK_DAEMON_STARTED_TRY_NUMBER = 200; // @@ -32,27 +33,37 @@ const Lbry: LbryTypes = { }, // Returns a human readable media type based on the content type or extension of a file that is returned by the sdk - getMediaType: (contentType: string, extname: ?string) => { - if (extname) { - const formats = [ - [/^(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], - [/^(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], - [/^(html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org)$/i, 'document'], - [/^(stl|obj|fbx|gcode)$/i, '3D-file'], - ]; + getMediaType: (contentType?: string, fileName: ?string) => { + const formats = [ + [/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], + [/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], + [/\.(h|go|ja|java|js|jsx|c|cpp|cs|css|rb|scss|sh|php|py)$/i, 'script'], + [/\.(json|csv|txt|log|md|markdown|docx|pdf|xml|yml|yaml)$/i, 'document'], + [/\.(pdf|odf|doc|docx|epub|org|rtf)$/i, 'e-book'], + [/\.(stl|obj|fbx|gcode)$/i, '3D-file'], + [/\.(cbr|cbt|cbz)$/i, 'comic-book'], + ]; + + const extName = mime.getExtension(contentType); + const fileExt = extName ? `.${extName}` : null; + const testString = fileName || fileExt; + + // Get mediaType from file extension + if (testString) { const res = formats.reduce((ret, testpair) => { - switch (testpair[0].test(ret)) { - case true: - return testpair[1]; - default: - return ret; - } - }, extname); - return res === extname ? 'unknown' : res; - } else if (contentType) { - // $FlowFixMe + const [regex, mediaType] = testpair; + + return regex.test(ret) ? mediaType : ret; + }, testString); + + if (res !== testString) return res; + } + + // Get mediaType from contentType + if (contentType) { return /^[^/]+/.exec(contentType)[0]; } + return 'unknown'; }, diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js index 0afe464..305ff4f 100644 --- a/src/redux/actions/file.js +++ b/src/redux/actions/file.js @@ -9,7 +9,7 @@ import { makeSelectStreamingUrlForUri } from 'redux/selectors/file'; type Dispatch = (action: any) => any; type GetState = () => { file: FileState }; -export function doFileGet(uri: string, saveFile: boolean = true) { +export function doFileGet(uri: string, saveFile: boolean = true, onSuccess?: GetResponse => any) { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.LOADING_FILE_STARTED, @@ -21,7 +21,8 @@ export function doFileGet(uri: string, saveFile: boolean = true) { // set save_file argument to True to save the file (old behaviour) Lbry.get({ uri, save_file: saveFile }) .then((streamInfo: GetResponse) => { - const timeout = streamInfo === null || typeof streamInfo !== 'object'; + const timeout = + streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; if (timeout) { dispatch({ @@ -39,8 +40,19 @@ export function doFileGet(uri: string, saveFile: boolean = true) { const { streaming_url: streamingUrl } = streamInfo; dispatch({ type: ACTIONS.PURCHASE_URI_COMPLETED, - data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null }, + data: { uri, streamingUrl }, }); + dispatch({ + type: ACTIONS.FETCH_FILE_INFO_COMPLETED, + data: { + fileInfo: streamInfo, + outpoint: streamInfo.outpoint, + }, + }); + + if (onSuccess) { + onSuccess(streamInfo); + } } }) .catch(() => { @@ -63,7 +75,12 @@ export function doFileGet(uri: string, saveFile: boolean = true) { }; } -export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile: boolean = true) { +export function doPurchaseUri( + uri: string, + costInfo: { cost: number }, + saveFile: boolean = true, + onSuccess?: GetResponse => any +) { return (dispatch: Dispatch, getState: GetState) => { dispatch({ type: ACTIONS.PURCHASE_URI_STARTED, @@ -98,7 +115,7 @@ export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile: return; } - dispatch(doFileGet(uri, saveFile)); + dispatch(doFileGet(uri, saveFile, onSuccess)); }; } diff --git a/src/redux/selectors/file.js b/src/redux/selectors/file.js index 7e0a1a1..3e5b4b8 100644 --- a/src/redux/selectors/file.js +++ b/src/redux/selectors/file.js @@ -1,5 +1,6 @@ // @flow import { createSelector } from 'reselect'; +import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; type State = { file: FileState }; @@ -31,8 +32,10 @@ export const selectLastPurchasedUri: (state: State) => string = createSelector( state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null ); -export const makeSelectStreamingUrlForUri = (uri: string): ((state: State) => {}) => +export const makeSelectStreamingUrlForUri = (uri: string) => createSelector( - selectPurchasedStreamingUrls, - streamingUrls => streamingUrls && streamingUrls[uri] + makeSelectFileInfoForUri(uri), + fileInfo => { + return fileInfo && fileInfo.streaming_url; + } ); diff --git a/src/redux/selectors/file_info.js b/src/redux/selectors/file_info.js index 7c045fe..7454209 100644 --- a/src/redux/selectors/file_info.js +++ b/src/redux/selectors/file_info.js @@ -3,9 +3,11 @@ import { selectIsFetchingClaimListMine, selectMyClaims, selectClaimsById, + makeSelectContentTypeForUri, } from 'redux/selectors/claims'; import { createSelector } from 'reselect'; import { buildURI } from 'lbryURI'; +import Lbry from 'lbry'; export const selectState = state => state.fileInfo || {}; @@ -72,7 +74,7 @@ export const selectFileInfosDownloaded = createSelector( return ( fileInfo && myClaimIds.indexOf(fileInfo.claim_id) === -1 && - (fileInfo.completed || fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0 ) + (fileInfo.completed || fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0) ); }) ); @@ -238,3 +240,41 @@ export const selectDownloadedUris = createSelector( .reverse() .map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`) ); + +export const makeSelectMediaTypeForUri = (uri: string) => + createSelector( + makeSelectFileInfoForUri(uri), + makeSelectContentTypeForUri(uri), + (fileInfo, contentType) => { + if (!fileInfo && !contentType) { + return undefined; + } + + const fileName = fileInfo && fileInfo.file_name; + return Lbry.getMediaType(contentType, fileName); + } + ); + +export const makeSelectUriIsStreamable = (uri: string) => + createSelector( + makeSelectMediaTypeForUri(uri), + mediaType => { + const isStreamable = ['audio', 'video', 'image'].indexOf(mediaType) !== -1; + return isStreamable; + } + ); + +export const makeSelectDownloadPathForUri = (uri: string) => + createSelector( + makeSelectFileInfoForUri(uri), + fileInfo => { + return fileInfo && fileInfo.download_path; + } + ); +export const makeSelectFileNameForUri = (uri: string) => + createSelector( + makeSelectFileInfoForUri(uri), + fileInfo => { + return fileInfo && fileInfo.file_name; + } + ); diff --git a/yarn.lock b/yarn.lock index 49dc513..182afdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3523,6 +3523,11 @@ mime-types@^2.1.12, mime-types@~2.1.17: dependencies: mime-db "~1.33.0" +mime@^2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"