Range request support for desktop #176

Merged
neb-b merged 4 commits from range-request into master 2019-08-13 19:33:59 +02:00
17 changed files with 334 additions and 270 deletions

348
dist/bundle.es.js vendored
View file

@ -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'));
@ -136,6 +137,7 @@ const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED';
const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED';
const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED';
const FETCH_FILE_INFO_FAILED = 'FETCH_FILE_INFO_FAILED';
const LOADING_VIDEO_STARTED = 'LOADING_VIDEO_STARTED';
const LOADING_VIDEO_COMPLETED = 'LOADING_VIDEO_COMPLETED';
const LOADING_VIDEO_FAILED = 'LOADING_VIDEO_FAILED';
@ -152,9 +154,6 @@ const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED';
const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED';
const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED';
const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI';
const LOADING_FILE_STARTED = 'LOADING_FILE_STARTED';
const LOADING_FILE_COMPLETED = 'LOADING_FILE_COMPLETED';
const LOADING_FILE_FAILED = 'LOADING_FILE_FAILED';
// Search
const SEARCH_START = 'SEARCH_START';
@ -365,6 +364,7 @@ var action_types = /*#__PURE__*/Object.freeze({
FILE_LIST_SUCCEEDED: FILE_LIST_SUCCEEDED,
FETCH_FILE_INFO_STARTED: FETCH_FILE_INFO_STARTED,
FETCH_FILE_INFO_COMPLETED: FETCH_FILE_INFO_COMPLETED,
FETCH_FILE_INFO_FAILED: FETCH_FILE_INFO_FAILED,
LOADING_VIDEO_STARTED: LOADING_VIDEO_STARTED,
LOADING_VIDEO_COMPLETED: LOADING_VIDEO_COMPLETED,
LOADING_VIDEO_FAILED: LOADING_VIDEO_FAILED,
@ -381,9 +381,6 @@ var action_types = /*#__PURE__*/Object.freeze({
PURCHASE_URI_COMPLETED: PURCHASE_URI_COMPLETED,
PURCHASE_URI_FAILED: PURCHASE_URI_FAILED,
DELETE_PURCHASED_URI: DELETE_PURCHASED_URI,
LOADING_FILE_STARTED: LOADING_FILE_STARTED,
LOADING_FILE_COMPLETED: LOADING_FILE_COMPLETED,
LOADING_FILE_FAILED: LOADING_FILE_FAILED,
SEARCH_START: SEARCH_START,
SEARCH_SUCCESS: SEARCH_SUCCESS,
SEARCH_FAIL: SEARCH_FAIL,
@ -696,23 +693,32 @@ 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
return (/^[^/]+/.exec(contentType)[0]
);
const [regex, mediaType] = testpair;
return regex.test(ret) ? mediaType : ret;
}, testString);
if (res !== testString) return res;
}
// Get mediaType from contentType
if (contentType) {
const matches = /^[^/]+/.exec(contentType);
if (matches) {
return matches[0];
}
}
return 'unknown';
},
@ -2447,7 +2453,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 +2592,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 || {};
@ -2596,65 +2623,76 @@ const selectFailedPurchaseUris = reselect.createSelector(selectState$4, state =>
const selectPurchasedUris = reselect.createSelector(selectState$4, state => state.purchasedUris);
const selectPurchasedStreamingUrls = reselect.createSelector(selectState$4, state => state.purchasedStreamingUrls);
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) {
return dispatch => {
function doFileGet(uri, saveFile = true, onSuccess) {
return (dispatch, getState) => {
const state = getState();
const { nout, txid } = makeSelectClaimForUri(uri)(state);
const outpoint = `${txid}:${nout}`;
dispatch({
type: LOADING_FILE_STARTED,
type: FETCH_FILE_INFO_STARTED,
data: {
uri
outpoint
}
});
// 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({
type: LOADING_FILE_FAILED,
data: { uri }
});
dispatch({
type: PURCHASE_URI_FAILED,
data: { uri }
type: FETCH_FILE_INFO_FAILED,
data: { outpoint }
});
dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true }));
} else {
// purchase was completed successfully
const { streaming_url: streamingUrl } = streamInfo;
dispatch({
type: PURCHASE_URI_COMPLETED,
data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null }
data: { uri }
});
dispatch({
type: FETCH_FILE_INFO_COMPLETED,
data: {
fileInfo: streamInfo,
outpoint: streamInfo.outpoint
}
});
if (onSuccess) {
onSuccess(streamInfo);
}
}
}).catch(() => {
dispatch({
type: LOADING_FILE_FAILED,
data: { uri }
});
dispatch({
type: PURCHASE_URI_FAILED,
data: { uri }
});
dispatch({
type: FETCH_FILE_INFO_FAILED,
data: { outpoint }
});
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 +2723,7 @@ function doPurchaseUri(uri, costInfo, saveFile = true) {
return;
}
dispatch(doFileGet(uri, saveFile));
dispatch(doFileGet(uri, saveFile, onSuccess));
};
}
@ -3831,8 +3869,6 @@ function contentReducer(state = defaultState$2, action) {
return state;
}
var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const reducers$2 = {};
const defaultState$3 = {
fileListPublishedSort: DATE_NEW,
@ -3887,20 +3923,27 @@ reducers$2[FETCH_FILE_INFO_COMPLETED] = (state, action) => {
});
};
reducers$2[FETCH_FILE_INFO_FAILED] = (state, action) => {
const { outpoint } = action.data;
const newFetching = Object.assign({}, state.fetching);
delete newFetching[outpoint];
return Object.assign({}, state, {
fetching: newFetching
});
};
reducers$2[DOWNLOADING_STARTED] = (state, action) => {
const { uri, outpoint, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
const newLoading = Object.assign({}, state.urisLoading);
newDownloading[outpoint] = true;
newByOutpoint[outpoint] = fileInfo;
delete newLoading[uri];
return Object.assign({}, state, {
downloadingByOutpoint: newDownloading,
urisLoading: newLoading,
byOutpoint: newByOutpoint
});
};
@ -3921,7 +3964,7 @@ 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];
@ -3961,36 +4004,6 @@ reducers$2[FILE_DELETE] = (state, action) => {
});
};
reducers$2[LOADING_VIDEO_STARTED] = (state, action) => {
const { uri } = action.data;
const newLoading = Object.assign({}, state.urisLoading);
newLoading[uri] = true;
const newErrors = _extends$8({}, state.errors);
if (uri in newErrors) delete newErrors[uri];
return Object.assign({}, state, {
urisLoading: newLoading,
errors: _extends$8({}, newErrors)
});
};
reducers$2[LOADING_VIDEO_FAILED] = (state, action) => {
const { uri } = action.data;
const newLoading = Object.assign({}, state.urisLoading);
delete newLoading[uri];
const newErrors = _extends$8({}, state.errors);
newErrors[uri] = true;
return Object.assign({}, state, {
urisLoading: newLoading,
errors: _extends$8({}, newErrors)
});
};
reducers$2[SET_FILE_LIST_SORT] = (state, action) => {
const pageSortStates = {
[PUBLISHED]: 'fileListPublishedSort',
@ -4010,13 +4023,12 @@ function fileInfoReducer(state = defaultState$3, action) {
return state;
}
var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const reducers$3 = {};
const defaultState$4 = {
failedPurchaseUris: [],
purchasedUris: [],
purchasedStreamingUrls: {},
purchaseUriErrorMessage: ''
};
@ -4027,17 +4039,16 @@ reducers$3[PURCHASE_URI_STARTED] = (state, action) => {
newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1);
}
return _extends$9({}, state, {
return _extends$8({}, state, {
failedPurchaseUris: newFailedPurchaseUris,
purchaseUriErrorMessage: ''
});
};
reducers$3[PURCHASE_URI_COMPLETED] = (state, action) => {
const { uri, streamingUrl } = action.data;
const { uri } = action.data;
const newPurchasedUris = state.purchasedUris.slice();
const newFailedPurchaseUris = state.failedPurchaseUris.slice();
const newPurchasedStreamingUrls = Object.assign({}, state.purchasedStreamingUrls);
if (!newPurchasedUris.includes(uri)) {
newPurchasedUris.push(uri);
@ -4045,14 +4056,10 @@ reducers$3[PURCHASE_URI_COMPLETED] = (state, action) => {
if (newFailedPurchaseUris.includes(uri)) {
newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1);
}
if (streamingUrl) {
newPurchasedStreamingUrls[uri] = streamingUrl;
}
return _extends$9({}, state, {
return _extends$8({}, state, {
failedPurchaseUris: newFailedPurchaseUris,
purchasedUris: newPurchasedUris,
purchasedStreamingUrls: newPurchasedStreamingUrls,
purchaseUriErrorMessage: ''
});
};
@ -4065,7 +4072,7 @@ reducers$3[PURCHASE_URI_FAILED] = (state, action) => {
newFailedPurchaseUris.push(uri);
}
return _extends$9({}, state, {
return _extends$8({}, state, {
failedPurchaseUris: newFailedPurchaseUris,
purchaseUriErrorMessage: error
});
@ -4078,7 +4085,7 @@ reducers$3[DELETE_PURCHASED_URI] = (state, action) => {
newPurchasedUris.splice(newPurchasedUris.indexOf(uri), 1);
}
return _extends$9({}, state, {
return _extends$8({}, state, {
purchasedUris: newPurchasedUris
});
};
@ -4089,7 +4096,7 @@ function fileReducer(state = defaultState$4, action) {
return state;
}
var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const defaultState$5 = {
notifications: [],
@ -4104,7 +4111,7 @@ const notificationsReducer = handleActions({
const newToasts = state.toasts.slice();
newToasts.push(toast);
return _extends$a({}, state, {
return _extends$9({}, state, {
toasts: newToasts
});
},
@ -4112,7 +4119,7 @@ const notificationsReducer = handleActions({
const newToasts = state.toasts.slice();
newToasts.shift();
return _extends$a({}, state, {
return _extends$9({}, state, {
toasts: newToasts
});
},
@ -4123,7 +4130,7 @@ const notificationsReducer = handleActions({
const newNotifications = state.notifications.slice();
newNotifications.push(notification);
return _extends$a({}, state, {
return _extends$9({}, state, {
notifications: newNotifications
});
},
@ -4134,7 +4141,7 @@ const notificationsReducer = handleActions({
notifications = notifications.map(pastNotification => pastNotification.id === notification.id ? notification : pastNotification);
return _extends$a({}, state, {
return _extends$9({}, state, {
notifications
});
},
@ -4143,7 +4150,7 @@ const notificationsReducer = handleActions({
let newNotifications = state.notifications.slice();
newNotifications = newNotifications.filter(notification => notification.id !== id);
return _extends$a({}, state, {
return _extends$9({}, state, {
notifications: newNotifications
});
},
@ -4154,7 +4161,7 @@ const notificationsReducer = handleActions({
const newErrors = state.errors.slice();
newErrors.push(error);
return _extends$a({}, state, {
return _extends$9({}, state, {
errors: newErrors
});
},
@ -4162,13 +4169,13 @@ const notificationsReducer = handleActions({
const newErrors = state.errors.slice();
newErrors.shift();
return _extends$a({}, state, {
return _extends$9({}, state, {
errors: newErrors
});
}
}, defaultState$5);
var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
@ -4205,17 +4212,17 @@ const defaultState$6 = {
const publishReducer = handleActions({
[UPDATE_PUBLISH_FORM]: (state, action) => {
const { data } = action;
return _extends$b({}, state, data);
return _extends$a({}, state, data);
},
[CLEAR_PUBLISH]: () => _extends$b({}, defaultState$6),
[PUBLISH_START]: state => _extends$b({}, state, {
[CLEAR_PUBLISH]: () => _extends$a({}, defaultState$6),
[PUBLISH_START]: state => _extends$a({}, state, {
publishing: true,
publishSuccess: false
}),
[PUBLISH_FAIL]: state => _extends$b({}, state, {
[PUBLISH_FAIL]: state => _extends$a({}, state, {
publishing: false
}),
[PUBLISH_SUCCESS]: state => _extends$b({}, state, {
[PUBLISH_SUCCESS]: state => _extends$a({}, state, {
publishing: false,
publishSuccess: true
}),
@ -4230,14 +4237,14 @@ const publishReducer = handleActions({
contentName: name
});
return _extends$b({}, defaultState$6, publishData, {
return _extends$a({}, defaultState$6, publishData, {
editingURI: uri,
uri: shortUri
});
}
}, defaultState$6);
var _extends$c = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const defaultState$7 = {
isActive: false, // does the user have any typed text in the search input
@ -4257,29 +4264,29 @@ const defaultState$7 = {
};
const searchReducer = handleActions({
[SEARCH_START]: state => _extends$c({}, state, {
[SEARCH_START]: state => _extends$b({}, state, {
searching: true
}),
[SEARCH_SUCCESS]: (state, action) => {
const { query, uris } = action.data;
return _extends$c({}, state, {
return _extends$b({}, state, {
searching: false,
urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris })
});
},
[SEARCH_FAIL]: state => _extends$c({}, state, {
[SEARCH_FAIL]: state => _extends$b({}, state, {
searching: false
}),
[UPDATE_SEARCH_QUERY]: (state, action) => _extends$c({}, state, {
[UPDATE_SEARCH_QUERY]: (state, action) => _extends$b({}, state, {
searchQuery: action.data.query,
isActive: true
}),
[UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$c({}, state, {
suggestions: _extends$c({}, state.suggestions, {
[UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$b({}, state, {
suggestions: _extends$b({}, state.suggestions, {
[action.data.query]: action.data.suggestions
})
}),
@ -4287,30 +4294,30 @@ const searchReducer = handleActions({
// sets isActive to false so the uri will be populated correctly if the
// user is on a file page. The search query will still be present on any
// other page
[DISMISS_NOTIFICATION]: state => _extends$c({}, state, {
[DISMISS_NOTIFICATION]: state => _extends$b({}, state, {
isActive: false
}),
[SEARCH_FOCUS]: state => _extends$c({}, state, {
[SEARCH_FOCUS]: state => _extends$b({}, state, {
focused: true
}),
[SEARCH_BLUR]: state => _extends$c({}, state, {
[SEARCH_BLUR]: state => _extends$b({}, state, {
focused: false
}),
[UPDATE_SEARCH_OPTIONS]: (state, action) => {
const { options: oldOptions } = state;
const newOptions = action.data;
const options = _extends$c({}, oldOptions, newOptions);
return _extends$c({}, state, {
const options = _extends$b({}, oldOptions, newOptions);
return _extends$b({}, state, {
options
});
}
}, defaultState$7);
var _extends$d = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$c = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function getDefaultKnownTags() {
return DEFAULT_FOLLOWED_TAGS.concat(DEFAULT_KNOWN_TAGS).reduce((tagsMap, tag) => _extends$d({}, tagsMap, {
return DEFAULT_FOLLOWED_TAGS.concat(DEFAULT_KNOWN_TAGS).reduce((tagsMap, tag) => _extends$c({}, tagsMap, {
[tag]: { name: tag }
}), {});
}
@ -4333,7 +4340,7 @@ const tagsReducer = handleActions({
newFollowedTags.push(name);
}
return _extends$d({}, state, {
return _extends$c({}, state, {
followedTags: newFollowedTags
});
},
@ -4342,10 +4349,10 @@ const tagsReducer = handleActions({
const { knownTags } = state;
const { name } = action.data;
let newKnownTags = _extends$d({}, knownTags);
let newKnownTags = _extends$c({}, knownTags);
newKnownTags[name] = { name };
return _extends$d({}, state, {
return _extends$c({}, state, {
knownTags: newKnownTags
});
},
@ -4354,11 +4361,11 @@ const tagsReducer = handleActions({
const { knownTags, followedTags } = state;
const { name } = action.data;
let newKnownTags = _extends$d({}, knownTags);
let newKnownTags = _extends$c({}, knownTags);
delete newKnownTags[name];
const newFollowedTags = followedTags.filter(tag => tag !== name);
return _extends$d({}, state, {
return _extends$c({}, state, {
knownTags: newKnownTags,
followedTags: newFollowedTags
});
@ -4389,7 +4396,7 @@ const blockedReducer = handleActions({
}
}, defaultState$9);
var _extends$e = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$d = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const buildDraftTransaction = () => ({
amount: undefined,
@ -4429,25 +4436,25 @@ const defaultState$a = {
};
const walletReducer = handleActions({
[FETCH_TRANSACTIONS_STARTED]: state => _extends$e({}, state, {
[FETCH_TRANSACTIONS_STARTED]: state => _extends$d({}, state, {
fetchingTransactions: true
}),
[FETCH_TRANSACTIONS_COMPLETED]: (state, action) => {
const byId = _extends$e({}, state.transactions);
const byId = _extends$d({}, state.transactions);
const { transactions } = action.data;
transactions.forEach(transaction => {
byId[transaction.txid] = transaction;
});
return _extends$e({}, state, {
return _extends$d({}, state, {
transactions: byId,
fetchingTransactions: false
});
},
[FETCH_SUPPORTS_STARTED]: state => _extends$e({}, state, {
[FETCH_SUPPORTS_STARTED]: state => _extends$d({}, state, {
fetchingSupports: true
}),
@ -4460,7 +4467,7 @@ const walletReducer = handleActions({
byOutpoint[`${txid}:${nout}`] = transaction;
});
return _extends$e({}, state, { supports: byOutpoint, fetchingSupports: false });
return _extends$d({}, state, { supports: byOutpoint, fetchingSupports: false });
},
[ABANDON_SUPPORT_STARTED]: (state, action) => {
@ -4469,7 +4476,7 @@ const walletReducer = handleActions({
currentlyAbandoning[outpoint] = true;
return _extends$e({}, state, {
return _extends$d({}, state, {
abandoningSupportsByOutpoint: currentlyAbandoning
});
},
@ -4482,56 +4489,56 @@ const walletReducer = handleActions({
delete currentlyAbandoning[outpoint];
delete byOutpoint[outpoint];
return _extends$e({}, state, {
return _extends$d({}, state, {
supports: byOutpoint,
abandoningSupportsById: currentlyAbandoning
});
},
[GET_NEW_ADDRESS_STARTED]: state => _extends$e({}, state, {
[GET_NEW_ADDRESS_STARTED]: state => _extends$d({}, state, {
gettingNewAddress: true
}),
[GET_NEW_ADDRESS_COMPLETED]: (state, action) => {
const { address } = action.data;
return _extends$e({}, state, { gettingNewAddress: false, receiveAddress: address });
return _extends$d({}, state, { gettingNewAddress: false, receiveAddress: address });
},
[UPDATE_BALANCE]: (state, action) => _extends$e({}, state, {
[UPDATE_BALANCE]: (state, action) => _extends$d({}, state, {
balance: action.data.balance
}),
[UPDATE_TOTAL_BALANCE]: (state, action) => _extends$e({}, state, {
[UPDATE_TOTAL_BALANCE]: (state, action) => _extends$d({}, state, {
totalBalance: action.data.totalBalance
}),
[CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$e({}, state, {
[CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$d({}, state, {
checkingAddressOwnership: true
}),
[CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$e({}, state, {
[CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$d({}, state, {
checkingAddressOwnership: false
}),
[SET_DRAFT_TRANSACTION_AMOUNT]: (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = _extends$e({}, oldDraft, { amount: parseFloat(action.data.amount) });
const newDraft = _extends$d({}, oldDraft, { amount: parseFloat(action.data.amount) });
return _extends$e({}, state, { draftTransaction: newDraft });
return _extends$d({}, state, { draftTransaction: newDraft });
},
[SET_DRAFT_TRANSACTION_ADDRESS]: (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = _extends$e({}, oldDraft, { address: action.data.address });
const newDraft = _extends$d({}, oldDraft, { address: action.data.address });
return _extends$e({}, state, { draftTransaction: newDraft });
return _extends$d({}, state, { draftTransaction: newDraft });
},
[SEND_TRANSACTION_STARTED]: state => {
const newDraftTransaction = _extends$e({}, state.draftTransaction, { sending: true });
const newDraftTransaction = _extends$d({}, state.draftTransaction, { sending: true });
return _extends$e({}, state, { draftTransaction: newDraftTransaction });
return _extends$d({}, state, { draftTransaction: newDraftTransaction });
},
[SEND_TRANSACTION_COMPLETED]: state => Object.assign({}, state, {
@ -4544,103 +4551,103 @@ const walletReducer = handleActions({
error: action.data.error
});
return _extends$e({}, state, { draftTransaction: newDraftTransaction });
return _extends$d({}, state, { draftTransaction: newDraftTransaction });
},
[SUPPORT_TRANSACTION_STARTED]: state => _extends$e({}, state, {
[SUPPORT_TRANSACTION_STARTED]: state => _extends$d({}, state, {
sendingSupport: true
}),
[SUPPORT_TRANSACTION_COMPLETED]: state => _extends$e({}, state, {
[SUPPORT_TRANSACTION_COMPLETED]: state => _extends$d({}, state, {
sendingSupport: false
}),
[SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$e({}, state, {
[SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$d({}, state, {
error: action.data.error,
sendingSupport: false
}),
[WALLET_STATUS_COMPLETED]: (state, action) => _extends$e({}, state, {
[WALLET_STATUS_COMPLETED]: (state, action) => _extends$d({}, state, {
walletIsEncrypted: action.result
}),
[WALLET_ENCRYPT_START]: state => _extends$e({}, state, {
[WALLET_ENCRYPT_START]: state => _extends$d({}, state, {
walletEncryptPending: true,
walletEncryptSucceded: null,
walletEncryptResult: null
}),
[WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$e({}, state, {
[WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$d({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: true,
walletEncryptResult: action.result
}),
[WALLET_ENCRYPT_FAILED]: (state, action) => _extends$e({}, state, {
[WALLET_ENCRYPT_FAILED]: (state, action) => _extends$d({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: false,
walletEncryptResult: action.result
}),
[WALLET_DECRYPT_START]: state => _extends$e({}, state, {
[WALLET_DECRYPT_START]: state => _extends$d({}, state, {
walletDecryptPending: true,
walletDecryptSucceded: null,
walletDecryptResult: null
}),
[WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$e({}, state, {
[WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$d({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: true,
walletDecryptResult: action.result
}),
[WALLET_DECRYPT_FAILED]: (state, action) => _extends$e({}, state, {
[WALLET_DECRYPT_FAILED]: (state, action) => _extends$d({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: false,
walletDecryptResult: action.result
}),
[WALLET_UNLOCK_START]: state => _extends$e({}, state, {
[WALLET_UNLOCK_START]: state => _extends$d({}, state, {
walletUnlockPending: true,
walletUnlockSucceded: null,
walletUnlockResult: null
}),
[WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$e({}, state, {
[WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$d({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: true,
walletUnlockResult: action.result
}),
[WALLET_UNLOCK_FAILED]: (state, action) => _extends$e({}, state, {
[WALLET_UNLOCK_FAILED]: (state, action) => _extends$d({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: false,
walletUnlockResult: action.result
}),
[WALLET_LOCK_START]: state => _extends$e({}, state, {
[WALLET_LOCK_START]: state => _extends$d({}, state, {
walletLockPending: false,
walletLockSucceded: null,
walletLockResult: null
}),
[WALLET_LOCK_COMPLETED]: (state, action) => _extends$e({}, state, {
[WALLET_LOCK_COMPLETED]: (state, action) => _extends$d({}, state, {
walletLockPending: false,
walletLockSucceded: true,
walletLockResult: action.result
}),
[WALLET_LOCK_FAILED]: (state, action) => _extends$e({}, state, {
[WALLET_LOCK_FAILED]: (state, action) => _extends$d({}, state, {
walletLockPending: false,
walletLockSucceded: false,
walletLockResult: action.result
}),
[SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$e({}, state, {
[SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$d({}, state, {
transactionListFilter: action.data
}),
[UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$e({}, state, {
[UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$d({}, state, {
latestBlock: action.data
})
}, defaultState$a);
@ -4656,14 +4663,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta
return state.positions[id] ? state.positions[id][outpoint] : null;
});
var _extends$f = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$e = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const selectState$7 = state => state.notifications || {};
const selectToast = reselect.createSelector(selectState$7, state => {
if (state.toasts.length) {
const { id, params } = state.toasts[0];
return _extends$f({
return _extends$e({
id
}, params);
}
@ -4842,12 +4849,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 +4874,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;
@ -4928,7 +4939,6 @@ exports.selectPendingClaims = selectPendingClaims;
exports.selectPlayingUri = selectPlayingUri;
exports.selectPublishFormValues = selectPublishFormValues;
exports.selectPurchaseUriErrorMessage = selectPurchaseUriErrorMessage;
exports.selectPurchasedStreamingUrls = selectPurchasedStreamingUrls;
exports.selectPurchasedUris = selectPurchasedUris;
exports.selectReceiveAddress = selectReceiveAddress;
exports.selectRecentTransactions = selectRecentTransactions;

View file

@ -38,7 +38,6 @@ declare type FileListItem = {
declare type FileState = {
failedPurchaseUris: Array<string>,
purchasedUris: Array<string>,
purchasedStreamingUrls: {},
};
declare type PurchaseUriCompleted = {
@ -53,7 +52,7 @@ declare type PurchaseUriFailed = {
type: ACTIONS.PURCHASE_URI_FAILED,
data: {
uri: string,
error: any
error: any,
},
};
@ -68,6 +67,6 @@ declare type PurchaseUriStarted = {
declare type DeletePurchasedUri = {
type: ACTIONS.DELETE_PURCHASED_URI,
data: {
uri: string
uri: string,
},
};

View file

@ -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,

4
dist/flow-typed/mime.js vendored Normal file
View file

@ -0,0 +1,4 @@
// @flow
declare module 'mime' {
declare module.exports: any;
}

5
flow-typed/File.js vendored
View file

@ -38,7 +38,6 @@ declare type FileListItem = {
declare type FileState = {
failedPurchaseUris: Array<string>,
purchasedUris: Array<string>,
purchasedStreamingUrls: {},
};
declare type PurchaseUriCompleted = {
@ -53,7 +52,7 @@ declare type PurchaseUriFailed = {
type: ACTIONS.PURCHASE_URI_FAILED,
data: {
uri: string,
error: any
error: any,
},
};
@ -68,6 +67,6 @@ declare type PurchaseUriStarted = {
declare type DeletePurchasedUri = {
type: ACTIONS.DELETE_PURCHASED_URI,
data: {
uri: string
uri: string,
},
};

2
flow-typed/Lbry.js vendored
View file

@ -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,

4
flow-typed/mime.js vendored Normal file
View file

@ -0,0 +1,4 @@
// @flow
declare module 'mime' {
declare module.exports: any;
}

View file

@ -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"

View file

@ -111,6 +111,7 @@ export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
export const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED';
export const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED';
export const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED';
export const FETCH_FILE_INFO_FAILED = 'FETCH_FILE_INFO_FAILED';
export const LOADING_VIDEO_STARTED = 'LOADING_VIDEO_STARTED';
export const LOADING_VIDEO_COMPLETED = 'LOADING_VIDEO_COMPLETED';
export const LOADING_VIDEO_FAILED = 'LOADING_VIDEO_FAILED';
@ -127,9 +128,6 @@ export const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED';
export const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED';
export const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED';
export const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI';
export const LOADING_FILE_STARTED = 'LOADING_FILE_STARTED';
export const LOADING_FILE_COMPLETED = 'LOADING_FILE_COMPLETED';
export const LOADING_FILE_FAILED = 'LOADING_FILE_FAILED';
// Search
export const SEARCH_START = 'SEARCH_START';

View file

@ -140,7 +140,6 @@ export { selectToast, selectError } from 'redux/selectors/notifications';
export {
selectFailedPurchaseUris,
selectPurchasedUris,
selectPurchasedStreamingUrls,
selectPurchaseUriErrorMessage,
selectLastPurchasedUri,
makeSelectStreamingUrlForUri,
@ -217,6 +216,10 @@ export {
selectFileListDownloadedSort,
selectFileListPublishedSort,
selectDownloadedUris,
makeSelectMediaTypeForUri,
makeSelectUriIsStreamable,
makeSelectDownloadPathForUri,
makeSelectFileNameForUri,
} from 'redux/selectors/file_info';
export {

View file

@ -1,5 +1,6 @@
// @flow
import 'proxy-polyfill';
import mime from 'mime';
const CHECK_DAEMON_STARTED_TRY_NUMBER = 200;
//
@ -32,27 +33,40 @@ 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
neb-b commented 2019-08-06 04:28:14 +02:00 (Migrated from github.com)
Review

I guess there have been some changes to this in the desktop codebase and we never moved over. Just copy pasting this in so we can switch to it.

Android doesn't use the second argument for this function so changing it should be fine.

I guess there have been some changes to this in the desktop codebase and we never moved over. Just copy pasting this in so we can switch to it. Android doesn't use the second argument for this function so changing it should be fine.
tzarebczan commented 2019-08-06 04:53:41 +02:00 (Migrated from github.com)
Review

I also mentioned to you that the SDK now returns a stream type:

      },
      "stream_type": "video",
      ],

The mapping is here - I think it should be able to work with some small adjustments (glaringly missing are fbx/gcode, but not sure if anyone uses those): 41b866c1ee/lbry/lbry/schema/mime_types.py

I also mentioned to you that the SDK now returns a stream type: ``` ... }, "stream_type": "video", ], ``` The mapping is here - I think it should be able to work with some small adjustments (glaringly missing are fbx/gcode, but not sure if anyone uses those): https://github.com/lbryio/lbry-sdk/blob/41b866c1eeb002aaa0e42bc71734f6879d3b4457/lbry/lbry/schema/mime_types.py
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
return /^[^/]+/.exec(contentType)[0];
const [regex, mediaType] = testpair;
return regex.test(ret) ? mediaType : ret;
}, testString);
if (res !== testString) return res;
}
// Get mediaType from contentType
if (contentType) {
const matches = /^[^/]+/.exec(contentType);
if (matches) {
return matches[0];
}
}
return 'unknown';
},

View file

@ -5,57 +5,70 @@ import { doToast } from 'redux/actions/notifications';
import { selectBalance } from 'redux/selectors/wallet';
import { makeSelectFileInfoForUri, selectDownloadingByOutpoint } from 'redux/selectors/file_info';
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
akinwale commented 2019-08-13 10:45:12 +02:00 (Migrated from github.com)
Review

Since doPurchaseUri also dispatches the same action, how do we differentiate between the two? I recall using a different action here because it's possible for a purchase to fail due to insufficient credits, the wallet being locked or some other condition, so get doesn't actually get called in those scenarios.

Since `doPurchaseUri` also dispatches the same action, how do we differentiate between the two? I recall using a different action here because it's possible for a purchase to fail due to insufficient credits, the wallet being locked or some other condition, so `get` doesn't actually get called in those scenarios.
neb-b commented 2019-08-13 16:57:54 +02:00 (Migrated from github.com)
Review

Ah that's a good point. I just searched for LOADING_FILE_ and didn't find anything so I figured it wasn't needed. That does make sense to have two though. I'll add it back. Maybe GET_FILE_XXX to signal that it's specifically for get calls?

Ah that's a good point. I just searched for `LOADING_FILE_` and didn't find anything so I figured it wasn't needed. That does make sense to have two though. I'll add it back. Maybe `GET_FILE_XXX` to signal that it's specifically for `get` calls?
akinwale commented 2019-08-13 17:13:46 +02:00 (Migrated from github.com)
Review

GET_FILE_XXX sounds perfect.

`GET_FILE_XXX` sounds perfect.
type Dispatch = (action: any) => any;
type GetState = () => { file: FileState };
export function doFileGet(uri: string, saveFile: boolean = true) {
return (dispatch: Dispatch) => {
export function doFileGet(uri: string, saveFile: boolean = true, onSuccess?: GetResponse => any) {
return (dispatch: Dispatch, getState: () => any) => {
const state = getState();
const { nout, txid } = makeSelectClaimForUri(uri)(state);
const outpoint = `${txid}:${nout}`;
dispatch({
type: ACTIONS.LOADING_FILE_STARTED,
type: ACTIONS.FETCH_FILE_INFO_STARTED,
data: {
uri,
outpoint,
},
});
// 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({
type: ACTIONS.LOADING_FILE_FAILED,
data: { uri },
});
dispatch({
type: ACTIONS.PURCHASE_URI_FAILED,
data: { uri },
type: ACTIONS.FETCH_FILE_INFO_FAILED,
data: { outpoint },
});
dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true }));
} else {
// purchase was completed successfully
const { streaming_url: streamingUrl } = streamInfo;
dispatch({
type: ACTIONS.PURCHASE_URI_COMPLETED,
data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null },
data: { uri },
});
dispatch({
type: ACTIONS.FETCH_FILE_INFO_COMPLETED,
data: {
fileInfo: streamInfo,
outpoint: streamInfo.outpoint,
},
});
if (onSuccess) {
onSuccess(streamInfo);
}
}
})
.catch(() => {
dispatch({
type: ACTIONS.LOADING_FILE_FAILED,
data: { uri },
});
dispatch({
type: ACTIONS.PURCHASE_URI_FAILED,
data: { uri },
});
dispatch({
type: ACTIONS.FETCH_FILE_INFO_FAILED,
data: { outpoint },
});
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,
})
);
@ -63,7 +76,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 +116,7 @@ export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile:
return;
}
dispatch(doFileGet(uri, saveFile));
dispatch(doFileGet(uri, saveFile, onSuccess));
};
}

View file

@ -5,7 +5,6 @@ const reducers = {};
const defaultState = {
failedPurchaseUris: [],
purchasedUris: [],
purchasedStreamingUrls: {},
purchaseUriErrorMessage: '',
};
@ -30,10 +29,9 @@ reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (
state: FileState,
action: PurchaseUriCompleted
): FileState => {
const { uri, streamingUrl } = action.data;
const { uri } = action.data;
const newPurchasedUris = state.purchasedUris.slice();
const newFailedPurchaseUris = state.failedPurchaseUris.slice();
const newPurchasedStreamingUrls = Object.assign({}, state.purchasedStreamingUrls);
if (!newPurchasedUris.includes(uri)) {
newPurchasedUris.push(uri);
@ -41,15 +39,11 @@ reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (
if (newFailedPurchaseUris.includes(uri)) {
newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1);
}
if (streamingUrl) {
newPurchasedStreamingUrls[uri] = streamingUrl;
}
return {
...state,
failedPurchaseUris: newFailedPurchaseUris,
purchasedUris: newPurchasedUris,
purchasedStreamingUrls: newPurchasedStreamingUrls,
purchaseUriErrorMessage: '',
};
};

View file

@ -57,20 +57,27 @@ reducers[ACTIONS.FETCH_FILE_INFO_COMPLETED] = (state, action) => {
});
};
reducers[ACTIONS.FETCH_FILE_INFO_FAILED] = (state, action) => {
const { outpoint } = action.data;
const newFetching = Object.assign({}, state.fetching);
delete newFetching[outpoint];
return Object.assign({}, state, {
fetching: newFetching,
});
};
reducers[ACTIONS.DOWNLOADING_STARTED] = (state, action) => {
const { uri, outpoint, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
const newLoading = Object.assign({}, state.urisLoading);
newDownloading[outpoint] = true;
newByOutpoint[outpoint] = fileInfo;
delete newLoading[uri];
return Object.assign({}, state, {
downloadingByOutpoint: newDownloading,
urisLoading: newLoading,
byOutpoint: newByOutpoint,
});
};
@ -91,7 +98,7 @@ reducers[ACTIONS.DOWNLOADING_PROGRESSED] = (state, action) => {
};
reducers[ACTIONS.DOWNLOADING_CANCELED] = (state, action) => {
const { outpoint } = action.data;
const { uri, outpoint } = action.data;
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
delete newDownloading[outpoint];
@ -131,36 +138,6 @@ reducers[ACTIONS.FILE_DELETE] = (state, action) => {
});
};
reducers[ACTIONS.LOADING_VIDEO_STARTED] = (state, action) => {
const { uri } = action.data;
const newLoading = Object.assign({}, state.urisLoading);
newLoading[uri] = true;
const newErrors = { ...state.errors };
if (uri in newErrors) delete newErrors[uri];
return Object.assign({}, state, {
urisLoading: newLoading,
errors: { ...newErrors },
});
};
reducers[ACTIONS.LOADING_VIDEO_FAILED] = (state, action) => {
const { uri } = action.data;
const newLoading = Object.assign({}, state.urisLoading);
delete newLoading[uri];
const newErrors = { ...state.errors };
newErrors[uri] = true;
return Object.assign({}, state, {
urisLoading: newLoading,
errors: { ...newErrors },
});
};
reducers[ACTIONS.SET_FILE_LIST_SORT] = (state, action) => {
const pageSortStates = {
[PAGES.PUBLISHED]: 'fileListPublishedSort',

View file

@ -1,5 +1,6 @@
// @flow
import { createSelector } from 'reselect';
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
type State = { file: FileState };
@ -20,19 +21,16 @@ export const selectPurchasedUris: (state: State) => Array<string> = createSelect
state => state.purchasedUris
);
export const selectPurchasedStreamingUrls: (state: State) => {} = createSelector(
selectState,
state => state.purchasedStreamingUrls
);
export const selectLastPurchasedUri: (state: State) => string = createSelector(
selectState,
state =>
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;
}
);

View file

@ -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)
(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;
}
);

View file

@ -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"