-- Revert to allow restoring commits ---
This reverts commit cb6a044584
.
This commit is contained in:
parent
d649e3563f
commit
263c09500f
27 changed files with 325 additions and 814 deletions
|
@ -8,7 +8,6 @@ const config = {
|
|||
WEB_SERVER_PORT: process.env.WEB_SERVER_PORT,
|
||||
LBRY_WEB_API: process.env.LBRY_WEB_API, //api.na-backend.odysee.com',
|
||||
LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API,
|
||||
LBRY_WEB_PUBLISH_API_V2: process.env.LBRY_WEB_PUBLISH_API_V2,
|
||||
LBRY_API_URL: process.env.LBRY_API_URL, //api.lbry.com',
|
||||
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //cdn.lbryplayer.xyz',
|
||||
LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API,
|
||||
|
|
|
@ -83,6 +83,9 @@ export const SYNC_APPLY_FAILED = 'SYNC_APPLY_FAILED';
|
|||
export const SYNC_APPLY_BAD_PASSWORD = 'SYNC_APPLY_BAD_PASSWORD';
|
||||
export const SYNC_RESET = 'SYNC_RESET';
|
||||
|
||||
// Lbry.tv
|
||||
export const UPDATE_UPLOAD_PROGRESS = 'UPDATE_UPLOAD_PROGRESS';
|
||||
|
||||
// User
|
||||
export const GENERATE_AUTH_TOKEN_FAILURE = 'GENERATE_AUTH_TOKEN_FAILURE';
|
||||
export const GENERATE_AUTH_TOKEN_STARTED = 'GENERATE_AUTH_TOKEN_STARTED';
|
||||
|
|
|
@ -27,6 +27,7 @@ export {
|
|||
doResetSync,
|
||||
doSyncEncryptAndDecrypt,
|
||||
} from 'redux/actions/sync';
|
||||
export { doUpdateUploadProgress } from './redux/actions/web';
|
||||
|
||||
// reducers
|
||||
export { authReducer } from './redux/reducers/auth';
|
||||
|
@ -36,6 +37,7 @@ export { filteredReducer } from './redux/reducers/filtered';
|
|||
// export { homepageReducer } from './redux/reducers/homepage';
|
||||
export { statsReducer } from './redux/reducers/stats';
|
||||
export { syncReducer } from './redux/reducers/sync';
|
||||
export { webReducer } from './redux/reducers/web';
|
||||
|
||||
// selectors
|
||||
export { selectAuthToken, selectIsAuthenticating } from './redux/selectors/auth';
|
||||
|
@ -68,3 +70,4 @@ export {
|
|||
selectSyncApplyErrorMessage,
|
||||
selectSyncApplyPasswordError,
|
||||
} from './redux/selectors/sync';
|
||||
export { selectCurrentUploads, selectUploadCount } from './redux/selectors/web';
|
||||
|
|
12
extras/lbryinc/redux/actions/web.js
Normal file
12
extras/lbryinc/redux/actions/web.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
export const doUpdateUploadProgress = (
|
||||
progress: string,
|
||||
params: { [key: string]: any },
|
||||
xhr: any
|
||||
) => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.UPDATE_UPLOAD_PROGRESS,
|
||||
data: { progress, params, xhr },
|
||||
});
|
62
extras/lbryinc/redux/reducers/web.js
Normal file
62
extras/lbryinc/redux/reducers/web.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
/*
|
||||
test mock:
|
||||
currentUploads: {
|
||||
'test#upload': {
|
||||
progress: 50,
|
||||
params: {
|
||||
name: 'steve',
|
||||
thumbnail_url: 'https://dev2.spee.ch/4/KMNtoSZ009fawGz59VG8PrID.jpeg',
|
||||
},
|
||||
},
|
||||
},
|
||||
*/
|
||||
|
||||
export type Params = {
|
||||
channel?: string,
|
||||
name: string,
|
||||
thumbnail_url: ?string,
|
||||
title: ?string,
|
||||
};
|
||||
|
||||
export type UploadItem = {
|
||||
progess: string,
|
||||
params: Params,
|
||||
xhr?: any,
|
||||
};
|
||||
|
||||
export type TvState = {
|
||||
currentUploads: { [key: string]: UploadItem },
|
||||
};
|
||||
|
||||
const reducers = {};
|
||||
|
||||
const defaultState: TvState = {
|
||||
currentUploads: {},
|
||||
};
|
||||
|
||||
reducers[ACTIONS.UPDATE_UPLOAD_PROGRESS] = (state: TvState, action) => {
|
||||
const { progress, params, xhr } = action.data;
|
||||
const key = params.channel ? `${params.name}#${params.channel}` : `${params.name}#anonymous`;
|
||||
let currentUploads;
|
||||
if (!progress) {
|
||||
currentUploads = Object.assign({}, state.currentUploads);
|
||||
Object.keys(currentUploads).forEach(k => {
|
||||
if (k === key) {
|
||||
delete currentUploads[key];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
currentUploads = Object.assign({}, state.currentUploads);
|
||||
currentUploads[key] = { progress, params, xhr };
|
||||
}
|
||||
return { ...state, currentUploads };
|
||||
};
|
||||
|
||||
export function webReducer(state: TvState = defaultState, action: any) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
return state;
|
||||
}
|
10
extras/lbryinc/redux/selectors/web.js
Normal file
10
extras/lbryinc/redux/selectors/web.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
const selectState = (state) => state.web || {};
|
||||
|
||||
export const selectCurrentUploads = (state) => selectState(state).currentUploads;
|
||||
|
||||
export const selectUploadCount = createSelector(
|
||||
selectCurrentUploads,
|
||||
(currentUploads) => currentUploads && Object.keys(currentUploads).length
|
||||
);
|
21
flow-typed/publish.js
vendored
21
flow-typed/publish.js
vendored
|
@ -52,24 +52,3 @@ declare type PublishParams = {
|
|||
nsfw: boolean,
|
||||
tags: Array<Tag>,
|
||||
};
|
||||
|
||||
declare type TusUploader = any;
|
||||
|
||||
declare type FileUploadSdkParams = {
|
||||
file_path: string,
|
||||
name: ?string,
|
||||
preview?: boolean,
|
||||
remote_url?: string,
|
||||
thumbnail_url?: string,
|
||||
title?: string,
|
||||
};
|
||||
|
||||
declare type FileUploadItem = {
|
||||
params: FileUploadSdkParams,
|
||||
file: File,
|
||||
fileFingerprint: string,
|
||||
progress: string,
|
||||
status?: string,
|
||||
uploader?: TusUploader | XMLHttpRequest,
|
||||
resumable: boolean,
|
||||
};
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
"rss": "^1.2.2",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
"tempy": "^0.6.0",
|
||||
"tus-js-client": "^2.3.0",
|
||||
"videojs-contrib-ads": "^6.9.0",
|
||||
"videojs-ima": "^1.11.0",
|
||||
"videojs-ima-player": "^0.5.6",
|
||||
|
|
|
@ -1291,16 +1291,6 @@
|
|||
"Select a file to upload": "Select a file to upload",
|
||||
"Select file to upload": "Select file to upload",
|
||||
"Url copied.": "Url copied.",
|
||||
"Failed to initiate upload (%err%)": "Failed to initiate upload (%err%)",
|
||||
"Invalid file": "Invalid file",
|
||||
"It appears to be a different or modified file.": "It appears to be a different or modified file.",
|
||||
"Please select the same file from the initial upload.": "Please select the same file from the initial upload.",
|
||||
"Cancel upload": "Cancel upload",
|
||||
"Cancel and remove the selected upload?": "Cancel and remove the selected upload?",
|
||||
"Select the file to resume upload...": "Select the file to resume upload...",
|
||||
"Stopped.": "Stopped.",
|
||||
"Resume": "Resume",
|
||||
"Retrying...": "Retrying...",
|
||||
"Uploading...": "Uploading...",
|
||||
"Creating...": "Creating...",
|
||||
"Use a URL": "Use a URL",
|
||||
|
@ -1440,6 +1430,7 @@
|
|||
"Log in to %SITE_NAME%": "Log in to %SITE_NAME%",
|
||||
"Log in": "Log in",
|
||||
"Not Yet": "Not Yet",
|
||||
"Preparing...": "Preparing...",
|
||||
"Confirm Upload": "Confirm Upload",
|
||||
"Confirm Edit": "Confirm Edit",
|
||||
"Create Livestream": "Create Livestream",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { hot } from 'react-hot-loader/root';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUploadCount } from 'lbryinc';
|
||||
import { selectGetSyncErrorMessage, selectSyncFatalError } from 'redux/selectors/sync';
|
||||
import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
|
||||
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
|
@ -21,7 +22,6 @@ import {
|
|||
selectActiveChannelClaim,
|
||||
selectIsReloadRequired,
|
||||
} from 'redux/selectors/app';
|
||||
import { selectUploadCount } from 'redux/selectors/publish';
|
||||
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
|
||||
import { doSyncLoop } from 'redux/actions/sync';
|
||||
import {
|
||||
|
|
|
@ -325,7 +325,7 @@ function PublishForm(props: Props) {
|
|||
submitLabel = __('Uploading...');
|
||||
}
|
||||
} else if (previewing) {
|
||||
submitLabel = <Spinner type="small" />;
|
||||
submitLabel = __('Preparing...');
|
||||
} else {
|
||||
if (isStillEditing) {
|
||||
submitLabel = __('Save');
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { doPublishResume, doUpdateUploadRemove } from 'redux/actions/publish';
|
||||
import { selectCurrentUploads, selectUploadCount } from 'redux/selectors/publish';
|
||||
import { selectCurrentUploads, selectUploadCount } from 'lbryinc';
|
||||
import WebUploadList from './view';
|
||||
|
||||
const select = (state) => ({
|
||||
const select = state => ({
|
||||
currentUploads: selectCurrentUploads(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
});
|
||||
|
||||
const perform = {
|
||||
doPublishResume,
|
||||
doUpdateUploadRemove,
|
||||
doOpenModal,
|
||||
};
|
||||
|
||||
export default connect(select, perform)(WebUploadList);
|
||||
export default connect(
|
||||
select,
|
||||
null
|
||||
)(WebUploadList);
|
||||
|
|
|
@ -1,155 +1,40 @@
|
|||
// @flow
|
||||
import React, { useState } from 'react';
|
||||
import FileSelector from 'component/common/file-selector';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import FileThumbnail from 'component/fileThumbnail';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import { serializeFileObj } from 'util/file';
|
||||
|
||||
type Props = {
|
||||
uploadItem: FileUploadItem,
|
||||
doPublishResume: (any) => void,
|
||||
doUpdateUploadRemove: (any) => void,
|
||||
doOpenModal: (string, {}) => void,
|
||||
params: UpdatePublishFormData,
|
||||
progress: string,
|
||||
xhr?: () => void,
|
||||
};
|
||||
|
||||
export default function WebUploadItem(props: Props) {
|
||||
const { uploadItem, doPublishResume, doUpdateUploadRemove, doOpenModal } = props;
|
||||
const { params, file, fileFingerprint, progress, status, resumable, uploader } = uploadItem;
|
||||
|
||||
const [showFileSelector, setShowFileSelector] = useState(false);
|
||||
|
||||
function handleFileChange(newFile: WebFile, clearName = true) {
|
||||
if (serializeFileObj(newFile) === fileFingerprint) {
|
||||
setShowFileSelector(false);
|
||||
doPublishResume({ ...params, file_path: newFile });
|
||||
} else {
|
||||
doOpenModal(MODALS.CONFIRM, {
|
||||
title: __('Invalid file'),
|
||||
subtitle: __('It appears to be a different or modified file.'),
|
||||
body: <p className="help--warning">{__('Please select the same file from the initial upload.')}</p>,
|
||||
onConfirm: (closeModal) => closeModal(),
|
||||
hideCancel: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
doOpenModal(MODALS.CONFIRM, {
|
||||
title: __('Cancel upload'),
|
||||
subtitle: __('Cancel and remove the selected upload?'),
|
||||
body: params.name ? <p className="empty">{`lbry://${params.name}`}</p> : undefined,
|
||||
onConfirm: (closeModal) => {
|
||||
if (uploader) {
|
||||
if (resumable) {
|
||||
// $FlowFixMe - couldn't resolve to TusUploader manually.
|
||||
uploader.abort(true); // TUS
|
||||
} else {
|
||||
uploader.abort(); // XHR
|
||||
}
|
||||
}
|
||||
doUpdateUploadRemove(params);
|
||||
closeModal();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function resolveProgressStr() {
|
||||
if (!uploader) {
|
||||
return __('Stopped.');
|
||||
}
|
||||
|
||||
if (resumable) {
|
||||
if (status) {
|
||||
switch (status) {
|
||||
case 'retry':
|
||||
return __('Retrying...');
|
||||
case 'error':
|
||||
return __('Failed.');
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
const progressInt = parseInt(progress);
|
||||
return progressInt === 100 ? __('Processing...') : __('Uploading...');
|
||||
}
|
||||
} else {
|
||||
return __('Uploading...');
|
||||
}
|
||||
}
|
||||
|
||||
function getRetryButton() {
|
||||
if (!resumable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (uploader) {
|
||||
// Should still be uploading. Don't show.
|
||||
return null;
|
||||
} else {
|
||||
// Refreshed or connection broken.
|
||||
const isFileActive = file instanceof File;
|
||||
return (
|
||||
<Button
|
||||
label={isFileActive ? __('Resume') : __('Retry')}
|
||||
button="link"
|
||||
onClick={() => {
|
||||
if (isFileActive) {
|
||||
doPublishResume({ ...params, file_path: file });
|
||||
} else {
|
||||
setShowFileSelector(true);
|
||||
}
|
||||
}}
|
||||
disabled={showFileSelector}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getCancelButton() {
|
||||
return <Button label={__('Cancel')} button="link" onClick={handleCancel} />;
|
||||
}
|
||||
|
||||
function getFileSelector() {
|
||||
return (
|
||||
<div className="claim-preview--padded">
|
||||
<FileSelector
|
||||
label={__('File')}
|
||||
onFileChosen={handleFileChange}
|
||||
// https://stackoverflow.com/questions/19107685/safari-input-type-file-accept-video-ignores-mp4-files
|
||||
accept={'video/mp4,video/x-m4v,video/*,audio/*'}
|
||||
placeholder={__('Select the file to resume upload...')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getProgressBar() {
|
||||
return (
|
||||
<>
|
||||
<div className="claim-upload__progress--label">lbry://{params.name}</div>
|
||||
<div className={'claim-upload__progress--outer card--inline'}>
|
||||
<div className={'claim-upload__progress--inner'} style={{ width: `${progress}%` }}>
|
||||
{resolveProgressStr()}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
const { params, progress, xhr } = props;
|
||||
|
||||
return (
|
||||
<li className={'web-upload-item claim-preview claim-preview--padded claim-preview--inactive card--inline'}>
|
||||
<li className={'claim-preview claim-preview--padded claim-preview--inactive card--inline'}>
|
||||
<FileThumbnail thumbnail={params.thumbnail_url} />
|
||||
<div className={'claim-preview-metadata'}>
|
||||
<div className="claim-preview-info">
|
||||
<div className="claim-preview__title">{params.title}</div>
|
||||
<div className="card__actions--inline">
|
||||
{getRetryButton()}
|
||||
{getCancelButton()}
|
||||
{xhr && (
|
||||
<div className="card__actions--inline">
|
||||
<Button
|
||||
button="link"
|
||||
onClick={() => {
|
||||
xhr.abort();
|
||||
}}
|
||||
label={__('Cancel')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<h2>lbry://{params.name}</h2>
|
||||
<div className={'claim-upload__progress--outer card--inline'}>
|
||||
<div className={'claim-upload__progress--inner'} style={{ width: `${progress}%` }}>
|
||||
Uploading...
|
||||
</div>
|
||||
</div>
|
||||
{showFileSelector && getFileSelector()}
|
||||
{!showFileSelector && getProgressBar()}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -3,16 +3,19 @@ import * as React from 'react';
|
|||
import Card from 'component/common/card';
|
||||
import WebUploadItem from './internal/web-upload-item';
|
||||
|
||||
export type UploadItem = {
|
||||
progess: string,
|
||||
params: UpdatePublishFormData,
|
||||
xhr?: { abort: () => void },
|
||||
};
|
||||
|
||||
type Props = {
|
||||
currentUploads: { [key: string]: FileUploadItem },
|
||||
currentUploads: { [key: string]: UploadItem },
|
||||
uploadCount: number,
|
||||
doPublishResume: (any) => void,
|
||||
doUpdateUploadRemove: (any) => void,
|
||||
doOpenModal: (string, {}) => void,
|
||||
};
|
||||
|
||||
export default function WebUploadList(props: Props) {
|
||||
const { currentUploads, uploadCount, doPublishResume, doUpdateUploadRemove, doOpenModal } = props;
|
||||
const { currentUploads, uploadCount } = props;
|
||||
|
||||
return (
|
||||
!!uploadCount && (
|
||||
|
@ -22,16 +25,8 @@ export default function WebUploadList(props: Props) {
|
|||
body={
|
||||
<section>
|
||||
{/* $FlowFixMe */}
|
||||
{Object.values(currentUploads).map((uploadItem) => (
|
||||
<WebUploadItem
|
||||
// $FlowFixMe
|
||||
key={`upload${uploadItem.params.name}`}
|
||||
// $FlowFixMe
|
||||
uploadItem={uploadItem}
|
||||
doPublishResume={doPublishResume}
|
||||
doUpdateUploadRemove={doUpdateUploadRemove}
|
||||
doOpenModal={doOpenModal}
|
||||
/>
|
||||
{Object.values(currentUploads).map(({ progress, params, xhr }) => (
|
||||
<WebUploadItem key={`upload${params.name}`} progress={progress} params={params} xhr={xhr} />
|
||||
))}
|
||||
</section>
|
||||
}
|
||||
|
|
|
@ -331,9 +331,6 @@ export const PUBLISH_FAIL = 'PUBLISH_FAIL';
|
|||
export const CLEAR_PUBLISH_ERROR = 'CLEAR_PUBLISH_ERROR';
|
||||
export const REMOVE_PENDING_PUBLISH = 'REMOVE_PENDING_PUBLISH';
|
||||
export const DO_PREPARE_EDIT = 'DO_PREPARE_EDIT';
|
||||
export const UPDATE_UPLOAD_ADD = 'UPDATE_UPLOAD_ADD';
|
||||
export const UPDATE_UPLOAD_PROGRESS = 'UPDATE_UPLOAD_PROGRESS';
|
||||
export const UPDATE_UPLOAD_REMOVE = 'UPDATE_UPLOAD_REMOVE';
|
||||
|
||||
// Media
|
||||
export const MEDIA_PLAY = 'MEDIA_PLAY';
|
||||
|
@ -494,6 +491,9 @@ export const FETCH_SUB_COUNT_STARTED = 'FETCH_SUB_COUNT_STARTED';
|
|||
export const FETCH_SUB_COUNT_FAILED = 'FETCH_SUB_COUNT_FAILED';
|
||||
export const FETCH_SUB_COUNT_COMPLETED = 'FETCH_SUB_COUNT_COMPLETED';
|
||||
|
||||
// Lbry.tv
|
||||
export const UPDATE_UPLOAD_PROGRESS = 'UPDATE_UPLOAD_PROGRESS';
|
||||
|
||||
// User
|
||||
export const GENERATE_AUTH_TOKEN_FAILURE = 'GENERATE_AUTH_TOKEN_FAILURE';
|
||||
export const GENERATE_AUTH_TOKEN_STARTED = 'GENERATE_AUTH_TOKEN_STARTED';
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
doAuthTokenRefresh,
|
||||
} from 'util/saved-passwords';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
import { LBRY_WEB_API, DEFAULT_LANGUAGE, LBRY_API_URL } from 'config';
|
||||
import { LBRY_WEB_API, DEFAULT_LANGUAGE, LBRY_API_URL, LBRY_WEB_PUBLISH_API } from 'config';
|
||||
|
||||
// Import 3rd-party styles before ours for the current way we are code-splitting.
|
||||
import 'scss/third-party.scss';
|
||||
|
@ -69,6 +69,7 @@ sdkAPIHost = LBRY_WEB_API;
|
|||
|
||||
export const SDK_API_PATH = `${sdkAPIHost}/api/v1`;
|
||||
const proxyURL = `${SDK_API_PATH}/proxy`;
|
||||
const publishURL = LBRY_WEB_PUBLISH_API; // || `${SDK_API_PATH}/proxy`;
|
||||
|
||||
Lbry.setDaemonConnectionString(proxyURL);
|
||||
|
||||
|
@ -78,6 +79,7 @@ Lbry.setOverride(
|
|||
new Promise((resolve, reject) => {
|
||||
apiPublishCallViaWeb(
|
||||
apiCall,
|
||||
publishURL,
|
||||
Lbry.getApiRequestHeaders() && Object.keys(Lbry.getApiRequestHeaders()).includes(X_LBRY_AUTH_TOKEN)
|
||||
? Lbry.getApiRequestHeaders()[X_LBRY_AUTH_TOKEN]
|
||||
: '',
|
||||
|
|
|
@ -5,9 +5,9 @@ import {
|
|||
selectMyClaimsPageItemCount,
|
||||
selectFetchingMyClaimsPageError,
|
||||
} from 'redux/selectors/claims';
|
||||
import { selectUploadCount } from 'redux/selectors/publish';
|
||||
import { doFetchClaimListMine, doCheckPendingClaims } from 'redux/actions/claims';
|
||||
import { doClearPublish } from 'redux/actions/publish';
|
||||
import { selectUploadCount } from 'lbryinc';
|
||||
import FileListPublished from './view';
|
||||
import { withRouter } from 'react-router';
|
||||
import { MY_CLAIMS_PAGE_SIZE, PAGE_PARAM, PAGE_SIZE_PARAM } from 'constants/claim';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import { connectRouter } from 'connected-react-router';
|
||||
import { costInfoReducer, blacklistReducer, filteredReducer, statsReducer } from 'lbryinc';
|
||||
import { costInfoReducer, blacklistReducer, filteredReducer, statsReducer, webReducer } from 'lbryinc';
|
||||
import { claimsReducer } from 'redux/reducers/claims';
|
||||
import { fileInfoReducer } from 'redux/reducers/file_info';
|
||||
import { walletReducer } from 'redux/reducers/wallet';
|
||||
|
@ -50,5 +50,6 @@ export default (history) =>
|
|||
user: userReducer,
|
||||
wallet: walletReducer,
|
||||
sync: syncReducer,
|
||||
web: webReducer,
|
||||
collections: collectionsReducer,
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ import { batchActions } from 'util/batch-actions';
|
|||
import { doCheckPendingClaims } from 'redux/actions/claims';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
selectMyActiveClaims,
|
||||
selectMyClaims,
|
||||
selectMyChannelClaims,
|
||||
// selectMyClaimsWithoutChannels,
|
||||
|
@ -48,147 +47,6 @@ function resolveClaimTypeForAnalytics(claim) {
|
|||
}
|
||||
|
||||
export const NO_FILE = '---';
|
||||
|
||||
function resolvePublishPayload(publishData, myClaimForUri, myChannels, preview) {
|
||||
const {
|
||||
name,
|
||||
bid,
|
||||
filePath,
|
||||
description,
|
||||
language,
|
||||
releaseTimeEdited,
|
||||
// license,
|
||||
licenseUrl,
|
||||
useLBRYUploader,
|
||||
licenseType,
|
||||
otherLicenseDescription,
|
||||
thumbnail,
|
||||
channel,
|
||||
title,
|
||||
contentIsFree,
|
||||
fee,
|
||||
// uri,
|
||||
tags,
|
||||
// locations,
|
||||
optimize,
|
||||
isLivestreamPublish,
|
||||
remoteFileUrl,
|
||||
} = publishData;
|
||||
|
||||
// Handle scenario where we have a claim that has the same name as a channel we are publishing with.
|
||||
const myClaimForUriEditing = myClaimForUri && myClaimForUri.name === name ? myClaimForUri : null;
|
||||
|
||||
let publishingLicense;
|
||||
switch (licenseType) {
|
||||
case COPYRIGHT:
|
||||
case OTHER:
|
||||
publishingLicense = otherLicenseDescription;
|
||||
break;
|
||||
default:
|
||||
publishingLicense = licenseType;
|
||||
}
|
||||
|
||||
// get the claim id from the channel name, we will use that instead
|
||||
const namedChannelClaim = myChannels ? myChannels.find((myChannel) => myChannel.name === channel) : null;
|
||||
const channelId = namedChannelClaim ? namedChannelClaim.claim_id : '';
|
||||
|
||||
const publishPayload: {
|
||||
name: ?string,
|
||||
bid: string,
|
||||
description?: string,
|
||||
channel_id?: string,
|
||||
file_path?: string,
|
||||
license_url?: string,
|
||||
license?: string,
|
||||
thumbnail_url?: string,
|
||||
release_time?: number,
|
||||
fee_currency?: string,
|
||||
fee_amount?: string,
|
||||
languages?: Array<string>,
|
||||
tags: Array<string>,
|
||||
locations?: Array<any>,
|
||||
blocking: boolean,
|
||||
optimize_file?: boolean,
|
||||
preview?: boolean,
|
||||
remote_url?: string,
|
||||
} = {
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
locations: [],
|
||||
bid: creditsToString(bid),
|
||||
languages: [language],
|
||||
tags: tags && tags.map((tag) => tag.name),
|
||||
thumbnail_url: thumbnail,
|
||||
blocking: true,
|
||||
preview: false,
|
||||
};
|
||||
|
||||
// Temporary solution to keep the same publish flow with the new tags api
|
||||
// Eventually we will allow users to enter their own tags on publish
|
||||
// `nsfw` will probably be removed
|
||||
if (remoteFileUrl) {
|
||||
publishPayload.remote_url = remoteFileUrl;
|
||||
}
|
||||
|
||||
if (publishingLicense) {
|
||||
publishPayload.license = publishingLicense;
|
||||
}
|
||||
|
||||
if (licenseUrl) {
|
||||
publishPayload.license_url = licenseUrl;
|
||||
}
|
||||
|
||||
if (thumbnail) {
|
||||
publishPayload.thumbnail_url = thumbnail;
|
||||
}
|
||||
|
||||
if (useLBRYUploader) {
|
||||
publishPayload.tags.push('lbry-first');
|
||||
}
|
||||
|
||||
// Set release time to curret date. On edits, keep original release/transaction time as release_time
|
||||
if (releaseTimeEdited) {
|
||||
publishPayload.release_time = releaseTimeEdited;
|
||||
} else if (myClaimForUriEditing && myClaimForUriEditing.value.release_time) {
|
||||
publishPayload.release_time = Number(myClaimForUri.value.release_time);
|
||||
} else if (myClaimForUriEditing && myClaimForUriEditing.timestamp) {
|
||||
publishPayload.release_time = Number(myClaimForUriEditing.timestamp);
|
||||
} else {
|
||||
publishPayload.release_time = Number(Math.round(Date.now() / 1000));
|
||||
}
|
||||
|
||||
if (channelId) {
|
||||
publishPayload.channel_id = channelId;
|
||||
}
|
||||
|
||||
if (myClaimForUriEditing && myClaimForUriEditing.value && myClaimForUriEditing.value.locations) {
|
||||
publishPayload.locations = myClaimForUriEditing.value.locations;
|
||||
}
|
||||
|
||||
if (!contentIsFree && fee && fee.currency && Number(fee.amount) > 0) {
|
||||
publishPayload.fee_currency = fee.currency;
|
||||
publishPayload.fee_amount = creditsToString(fee.amount);
|
||||
}
|
||||
|
||||
if (optimize) {
|
||||
publishPayload.optimize_file = true;
|
||||
}
|
||||
|
||||
// Only pass file on new uploads, not metadata only edits.
|
||||
// The sdk will figure it out
|
||||
if (filePath && !isLivestreamPublish) {
|
||||
publishPayload.file_path = filePath;
|
||||
}
|
||||
|
||||
if (preview) {
|
||||
publishPayload.preview = true;
|
||||
publishPayload.optimize_file = false;
|
||||
}
|
||||
|
||||
return publishPayload;
|
||||
}
|
||||
|
||||
export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispatch: Dispatch, getState: () => {}) => {
|
||||
const publishPreview = (previewResponse) => {
|
||||
dispatch(
|
||||
|
@ -290,62 +148,6 @@ export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispat
|
|||
dispatch(doPublish(publishSuccess, publishFail));
|
||||
};
|
||||
|
||||
export const doPublishResume = (publishPayload: any) => (dispatch: Dispatch, getState: () => {}) => {
|
||||
const publishSuccess = (successResponse, lbryFirstError) => {
|
||||
const state = getState();
|
||||
const myClaimIds: Set<string> = selectMyActiveClaims(state);
|
||||
|
||||
const pendingClaim = successResponse.outputs[0];
|
||||
const { permanent_url: url } = pendingClaim;
|
||||
|
||||
analytics.apiLogPublish(pendingClaim);
|
||||
|
||||
// We have to fake a temp claim until the new pending one is returned by claim_list_mine
|
||||
// We can't rely on claim_list_mine because there might be some delay before the new claims are returned
|
||||
// Doing this allows us to show the pending claim immediately, it will get overwritten by the real one
|
||||
const isEdit = myClaimIds.has(pendingClaim.claim_id);
|
||||
|
||||
const actions = [];
|
||||
|
||||
actions.push({
|
||||
type: ACTIONS.PUBLISH_SUCCESS,
|
||||
data: {
|
||||
type: resolveClaimTypeForAnalytics(pendingClaim),
|
||||
},
|
||||
});
|
||||
|
||||
actions.push({
|
||||
type: ACTIONS.UPDATE_PENDING_CLAIMS,
|
||||
data: {
|
||||
claims: [pendingClaim],
|
||||
},
|
||||
});
|
||||
|
||||
dispatch(batchActions(...actions));
|
||||
|
||||
dispatch(
|
||||
doOpenModal(MODALS.PUBLISH, {
|
||||
uri: url,
|
||||
isEdit,
|
||||
lbryFirstError,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(doCheckPendingClaims());
|
||||
};
|
||||
|
||||
const publishFail = (error) => {
|
||||
const actions = [];
|
||||
actions.push({
|
||||
type: ACTIONS.PUBLISH_FAIL,
|
||||
});
|
||||
actions.push(doError(error.message));
|
||||
dispatch(batchActions(...actions));
|
||||
};
|
||||
|
||||
dispatch(doPublish(publishSuccess, publishFail, false, publishPayload));
|
||||
};
|
||||
|
||||
export const doResetThumbnailStatus = () => (dispatch: Dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.UPDATE_PUBLISH_FORM,
|
||||
|
@ -571,7 +373,7 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
|
|||
dispatch({ type: ACTIONS.DO_PREPARE_EDIT, data: publishData });
|
||||
};
|
||||
|
||||
export const doPublish = (success: Function, fail: Function, preview: Function, payload: any) => (
|
||||
export const doPublish = (success: Function, fail: Function, preview: Function) => (
|
||||
dispatch: Dispatch,
|
||||
getState: () => {}
|
||||
) => {
|
||||
|
@ -586,9 +388,139 @@ export const doPublish = (success: Function, fail: Function, preview: Function,
|
|||
// get redux publish form
|
||||
const publishData = selectPublishFormValues(state);
|
||||
|
||||
const publishPayload = payload || resolvePublishPayload(publishData, myClaimForUri, myChannels, preview);
|
||||
// destructure the data values
|
||||
const {
|
||||
name,
|
||||
bid,
|
||||
filePath,
|
||||
description,
|
||||
language,
|
||||
releaseTimeEdited,
|
||||
// license,
|
||||
licenseUrl,
|
||||
useLBRYUploader,
|
||||
licenseType,
|
||||
otherLicenseDescription,
|
||||
thumbnail,
|
||||
channel,
|
||||
title,
|
||||
contentIsFree,
|
||||
fee,
|
||||
// uri,
|
||||
tags,
|
||||
// locations,
|
||||
optimize,
|
||||
isLivestreamPublish,
|
||||
remoteFileUrl,
|
||||
} = publishData;
|
||||
|
||||
// Handle scenario where we have a claim that has the same name as a channel we are publishing with.
|
||||
const myClaimForUriEditing = myClaimForUri && myClaimForUri.name === name ? myClaimForUri : null;
|
||||
|
||||
let publishingLicense;
|
||||
switch (licenseType) {
|
||||
case COPYRIGHT:
|
||||
case OTHER:
|
||||
publishingLicense = otherLicenseDescription;
|
||||
break;
|
||||
default:
|
||||
publishingLicense = licenseType;
|
||||
}
|
||||
|
||||
// get the claim id from the channel name, we will use that instead
|
||||
const namedChannelClaim = myChannels ? myChannels.find((myChannel) => myChannel.name === channel) : null;
|
||||
const channelId = namedChannelClaim ? namedChannelClaim.claim_id : '';
|
||||
|
||||
const publishPayload: {
|
||||
name: ?string,
|
||||
bid: string,
|
||||
description?: string,
|
||||
channel_id?: string,
|
||||
file_path?: string,
|
||||
license_url?: string,
|
||||
license?: string,
|
||||
thumbnail_url?: string,
|
||||
release_time?: number,
|
||||
fee_currency?: string,
|
||||
fee_amount?: string,
|
||||
languages?: Array<string>,
|
||||
tags: Array<string>,
|
||||
locations?: Array<any>,
|
||||
blocking: boolean,
|
||||
optimize_file?: boolean,
|
||||
preview?: boolean,
|
||||
remote_url?: string,
|
||||
} = {
|
||||
name,
|
||||
title,
|
||||
description,
|
||||
locations: [],
|
||||
bid: creditsToString(bid),
|
||||
languages: [language],
|
||||
tags: tags && tags.map((tag) => tag.name),
|
||||
thumbnail_url: thumbnail,
|
||||
blocking: true,
|
||||
preview: false,
|
||||
};
|
||||
// Temporary solution to keep the same publish flow with the new tags api
|
||||
// Eventually we will allow users to enter their own tags on publish
|
||||
// `nsfw` will probably be removed
|
||||
if (remoteFileUrl) {
|
||||
publishPayload.remote_url = remoteFileUrl;
|
||||
}
|
||||
|
||||
if (publishingLicense) {
|
||||
publishPayload.license = publishingLicense;
|
||||
}
|
||||
|
||||
if (licenseUrl) {
|
||||
publishPayload.license_url = licenseUrl;
|
||||
}
|
||||
|
||||
if (thumbnail) {
|
||||
publishPayload.thumbnail_url = thumbnail;
|
||||
}
|
||||
|
||||
if (useLBRYUploader) {
|
||||
publishPayload.tags.push('lbry-first');
|
||||
}
|
||||
|
||||
// Set release time to curret date. On edits, keep original release/transaction time as release_time
|
||||
if (releaseTimeEdited) {
|
||||
publishPayload.release_time = releaseTimeEdited;
|
||||
} else if (myClaimForUriEditing && myClaimForUriEditing.value.release_time) {
|
||||
publishPayload.release_time = Number(myClaimForUri.value.release_time);
|
||||
} else if (myClaimForUriEditing && myClaimForUriEditing.timestamp) {
|
||||
publishPayload.release_time = Number(myClaimForUriEditing.timestamp);
|
||||
} else {
|
||||
publishPayload.release_time = Number(Math.round(Date.now() / 1000));
|
||||
}
|
||||
|
||||
if (channelId) {
|
||||
publishPayload.channel_id = channelId;
|
||||
}
|
||||
|
||||
if (myClaimForUriEditing && myClaimForUriEditing.value && myClaimForUriEditing.value.locations) {
|
||||
publishPayload.locations = myClaimForUriEditing.value.locations;
|
||||
}
|
||||
|
||||
if (!contentIsFree && fee && fee.currency && Number(fee.amount) > 0) {
|
||||
publishPayload.fee_currency = fee.currency;
|
||||
publishPayload.fee_amount = creditsToString(fee.amount);
|
||||
}
|
||||
|
||||
if (optimize) {
|
||||
publishPayload.optimize_file = true;
|
||||
}
|
||||
|
||||
// Only pass file on new uploads, not metadata only edits.
|
||||
// The sdk will figure it out
|
||||
if (filePath && !isLivestreamPublish) publishPayload.file_path = filePath;
|
||||
|
||||
if (preview) {
|
||||
publishPayload.preview = true;
|
||||
publishPayload.optimize_file = false;
|
||||
|
||||
return Lbry.publish(publishPayload).then((previewResponse: PublishResponse) => {
|
||||
return preview(previewResponse);
|
||||
}, fail);
|
||||
|
@ -688,35 +620,3 @@ export const doCheckReflectingFiles = () => (dispatch: Dispatch, getState: GetSt
|
|||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
export function doUpdateUploadAdd(
|
||||
file: File | string,
|
||||
params: { [key: string]: any },
|
||||
uploader: TusUploader | XMLHttpRequest
|
||||
) {
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({
|
||||
type: ACTIONS.UPDATE_UPLOAD_ADD,
|
||||
data: { file, params, uploader },
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const doUpdateUploadProgress = (props: {
|
||||
params: { [key: string]: any },
|
||||
progress?: string,
|
||||
status?: string,
|
||||
}) => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.UPDATE_UPLOAD_PROGRESS,
|
||||
data: props,
|
||||
});
|
||||
|
||||
export function doUpdateUploadRemove(params: { [key: string]: any }) {
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({
|
||||
type: ACTIONS.UPDATE_UPLOAD_REMOVE,
|
||||
data: { params },
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
// @flow
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
import { buildURI } from 'util/lbryURI';
|
||||
import { serializeFileObj } from 'util/file';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
|
||||
import { CHANNEL_ANONYMOUS } from 'constants/claim';
|
||||
|
||||
const getKeyFromParam = (params) => `${params.name}#${params.channel || 'anonymous'}`;
|
||||
|
||||
type PublishState = {
|
||||
editingURI: ?string,
|
||||
fileText: ?string,
|
||||
|
@ -41,7 +38,6 @@ type PublishState = {
|
|||
tags: Array<string>,
|
||||
optimize: boolean,
|
||||
useLBRYUploader: boolean,
|
||||
currentUploads: { [key: string]: FileUploadItem },
|
||||
};
|
||||
|
||||
const defaultState: PublishState = {
|
||||
|
@ -82,7 +78,6 @@ const defaultState: PublishState = {
|
|||
publishError: undefined,
|
||||
optimize: false,
|
||||
useLBRYUploader: false,
|
||||
currentUploads: {},
|
||||
};
|
||||
|
||||
export const publishReducer = handleActions(
|
||||
|
@ -101,7 +96,6 @@ export const publishReducer = handleActions(
|
|||
bid: state.bid,
|
||||
optimize: state.optimize,
|
||||
language: state.language,
|
||||
currentUploads: state.currentUploads,
|
||||
}),
|
||||
[ACTIONS.PUBLISH_START]: (state: PublishState): PublishState => ({
|
||||
...state,
|
||||
|
@ -133,76 +127,8 @@ export const publishReducer = handleActions(
|
|||
...publishData,
|
||||
editingURI: uri,
|
||||
uri: shortUri,
|
||||
currentUploads: state.currentUploads,
|
||||
};
|
||||
},
|
||||
[ACTIONS.UPDATE_UPLOAD_ADD]: (state: PublishState, action) => {
|
||||
const { file, params, uploader } = action.data;
|
||||
const key = getKeyFromParam(params);
|
||||
const currentUploads = Object.assign({}, state.currentUploads);
|
||||
|
||||
currentUploads[key] = {
|
||||
file,
|
||||
fileFingerprint: file ? serializeFileObj(file) : undefined, // TODO: get hash instead?
|
||||
progress: '0',
|
||||
params,
|
||||
uploader,
|
||||
resumable: !(uploader instanceof XMLHttpRequest),
|
||||
};
|
||||
|
||||
return { ...state, currentUploads };
|
||||
},
|
||||
[ACTIONS.UPDATE_UPLOAD_PROGRESS]: (state: PublishState, action) => {
|
||||
const { params, progress, status } = action.data;
|
||||
const key = getKeyFromParam(params);
|
||||
const currentUploads = Object.assign({}, state.currentUploads);
|
||||
|
||||
if (!currentUploads[key]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
currentUploads[key].progress = progress;
|
||||
delete currentUploads[key].status;
|
||||
} else if (status) {
|
||||
currentUploads[key].status = status;
|
||||
if (status === 'error') {
|
||||
delete currentUploads[key].uploader;
|
||||
}
|
||||
}
|
||||
|
||||
return { ...state, currentUploads };
|
||||
},
|
||||
[ACTIONS.UPDATE_UPLOAD_REMOVE]: (state: PublishState, action) => {
|
||||
const { params } = action.data;
|
||||
const key = getKeyFromParam(params);
|
||||
const currentUploads = Object.assign({}, state.currentUploads);
|
||||
|
||||
delete currentUploads[key];
|
||||
|
||||
return { ...state, currentUploads };
|
||||
},
|
||||
[ACTIONS.REHYDRATE]: (state: PublishState, action) => {
|
||||
if (action && action.payload && action.payload.publish) {
|
||||
const newPublish = { ...action.payload.publish };
|
||||
|
||||
// Cleanup for 'publish::currentUploads'
|
||||
if (newPublish.currentUploads) {
|
||||
Object.keys(newPublish.currentUploads).forEach((key) => {
|
||||
const params = newPublish.currentUploads[key].params;
|
||||
if (!params || Object.keys(params).length === 0) {
|
||||
delete newPublish.currentUploads[key];
|
||||
} else {
|
||||
delete newPublish.currentUploads[key].uploader;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return newPublish;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
||||
|
|
|
@ -119,10 +119,3 @@ export const selectTakeOverAmount = createSelector(
|
|||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectCurrentUploads = (state) => selectState(state).currentUploads;
|
||||
|
||||
export const selectUploadCount = createSelector(
|
||||
selectCurrentUploads,
|
||||
(currentUploads) => currentUploads && Object.keys(currentUploads).length
|
||||
);
|
||||
|
|
|
@ -363,11 +363,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.claim-upload__progress--label {
|
||||
font-size: var(--font-small);
|
||||
color: var(--color-text-subtitle);
|
||||
}
|
||||
|
||||
.claim-upload__progress--outer {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -862,17 +857,3 @@
|
|||
margin-top: var(--spacing-s);
|
||||
}
|
||||
}
|
||||
|
||||
.web-upload-item.claim-preview {
|
||||
@media (max-width: $breakpoint-small) {
|
||||
display: block;
|
||||
|
||||
.media__thumb {
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
|
||||
.claim-preview-metadata {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export function serializeFileObj(file: File) {
|
||||
return `${file.name}#${file.type}#${file.size}`;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
// @flow
|
||||
|
||||
// https://api.na-backend.odysee.com/api/v1/proxy currently expects publish to
|
||||
// consist of a multipart/form-data POST request with:
|
||||
// - 'file' binary
|
||||
// - 'json_payload' publish params to be passed to the server's sdk.
|
||||
|
||||
import { X_LBRY_AUTH_TOKEN } from '../../ui/constants/token';
|
||||
import { doUpdateUploadAdd, doUpdateUploadProgress, doUpdateUploadRemove } from '../../ui/redux/actions/publish';
|
||||
import { LBRY_WEB_PUBLISH_API } from 'config';
|
||||
|
||||
const ENDPOINT = LBRY_WEB_PUBLISH_API;
|
||||
const ENDPOINT_METHOD = 'publish';
|
||||
|
||||
export function makeUploadRequest(
|
||||
token: string,
|
||||
params: FileUploadSdkParams,
|
||||
file: File | string,
|
||||
isPreview?: boolean
|
||||
) {
|
||||
const { remote_url: remoteUrl } = params;
|
||||
|
||||
const body = new FormData();
|
||||
|
||||
if (file) {
|
||||
body.append('file', file);
|
||||
delete params['remote_url'];
|
||||
} else if (remoteUrl) {
|
||||
body.append('remote_url', remoteUrl);
|
||||
delete params['remote_url'];
|
||||
}
|
||||
|
||||
const jsonPayload = JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: ENDPOINT_METHOD,
|
||||
params,
|
||||
id: new Date().getTime(),
|
||||
});
|
||||
|
||||
// no fileData? do the livestream remote publish
|
||||
body.append('json_payload', jsonPayload);
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', ENDPOINT);
|
||||
xhr.setRequestHeader(X_LBRY_AUTH_TOKEN, token);
|
||||
xhr.responseType = 'json';
|
||||
xhr.upload.onprogress = (e) => {
|
||||
const percentage = ((e.loaded / e.total) * 100).toFixed(2);
|
||||
window.store.dispatch(doUpdateUploadProgress({ params, progress: percentage }));
|
||||
};
|
||||
xhr.onload = () => {
|
||||
window.store.dispatch(doUpdateUploadRemove(params));
|
||||
resolve(xhr);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress({ params, status: 'error' }));
|
||||
reject(new Error(__('There was a problem with your upload. Please try again.')));
|
||||
};
|
||||
xhr.onabort = () => {
|
||||
window.store.dispatch(doUpdateUploadRemove(params));
|
||||
};
|
||||
|
||||
if (!isPreview) {
|
||||
window.store.dispatch(doUpdateUploadAdd(file, params, xhr));
|
||||
}
|
||||
|
||||
xhr.send(body);
|
||||
});
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
// @flow
|
||||
import * as tus from 'tus-js-client';
|
||||
import { X_LBRY_AUTH_TOKEN } from '../../ui/constants/token';
|
||||
import { doUpdateUploadAdd, doUpdateUploadProgress, doUpdateUploadRemove } from '../../ui/redux/actions/publish';
|
||||
import { LBRY_WEB_PUBLISH_API_V2 } from 'config';
|
||||
|
||||
const RESUMABLE_ENDPOINT = LBRY_WEB_PUBLISH_API_V2;
|
||||
const RESUMABLE_ENDPOINT_METHOD = 'publish';
|
||||
const UPLOAD_CHUNK_SIZE_BYTE = 100000000;
|
||||
|
||||
export function makeResumableUploadRequest(
|
||||
token: string,
|
||||
params: FileUploadSdkParams,
|
||||
file: File | string,
|
||||
isPreview?: boolean
|
||||
) {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
if (!RESUMABLE_ENDPOINT) {
|
||||
reject(new Error('Publish: endpoint undefined'));
|
||||
}
|
||||
|
||||
// @if NODE_ENV!='production'
|
||||
if (params.remote_url) {
|
||||
reject(new Error('Publish: v2 does not support remote_url'));
|
||||
}
|
||||
// @endif
|
||||
|
||||
const jsonPayload = JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: RESUMABLE_ENDPOINT_METHOD,
|
||||
params,
|
||||
id: new Date().getTime(),
|
||||
});
|
||||
|
||||
const uploader = new tus.Upload(file, {
|
||||
endpoint: RESUMABLE_ENDPOINT,
|
||||
chunkSize: UPLOAD_CHUNK_SIZE_BYTE,
|
||||
retryDelays: [0, 3000, 3000],
|
||||
parallelUploads: 1,
|
||||
removeFingerprintOnSuccess: true,
|
||||
headers: { [X_LBRY_AUTH_TOKEN]: token },
|
||||
metadata: {
|
||||
filename: file instanceof File ? file.name : file,
|
||||
filetype: file instanceof File ? file.type : undefined,
|
||||
},
|
||||
onShouldRetry: (err, retryAttempt, options) => {
|
||||
window.store.dispatch(doUpdateUploadProgress({ params, status: 'retry' }));
|
||||
const FORBIDDEN_ERROR = 403;
|
||||
const status = err.originalResponse ? err.originalResponse.getStatus() : 0;
|
||||
return status !== FORBIDDEN_ERROR;
|
||||
},
|
||||
onError: (error) => {
|
||||
window.store.dispatch(doUpdateUploadProgress({ params, status: 'error' }));
|
||||
reject(new Error(error));
|
||||
},
|
||||
onProgress: (bytesUploaded, bytesTotal) => {
|
||||
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
|
||||
window.store.dispatch(doUpdateUploadProgress({ params, progress: percentage }));
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Notify lbrynet server
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', `${uploader.url}/notify`);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.setRequestHeader('Tus-Resumable', '1.0.0');
|
||||
xhr.setRequestHeader(X_LBRY_AUTH_TOKEN, token);
|
||||
xhr.responseType = 'json';
|
||||
xhr.onload = () => {
|
||||
window.store.dispatch(doUpdateUploadRemove(params));
|
||||
resolve(xhr);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
reject(new Error(__('There was a problem with your upload. Please try again.')));
|
||||
};
|
||||
xhr.onabort = () => {
|
||||
window.store.dispatch(doUpdateUploadRemove(params));
|
||||
};
|
||||
|
||||
xhr.send(jsonPayload);
|
||||
},
|
||||
});
|
||||
|
||||
uploader
|
||||
.findPreviousUploads()
|
||||
.then((previousUploads) => {
|
||||
if (previousUploads.length > 0) {
|
||||
uploader.resumeFromPreviousUpload(previousUploads[0]);
|
||||
}
|
||||
|
||||
if (!isPreview) {
|
||||
window.store.dispatch(doUpdateUploadAdd(file, params, uploader));
|
||||
}
|
||||
|
||||
uploader.start();
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(new Error(__('Failed to initiate upload (%err%)', { err })));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,16 +1,22 @@
|
|||
// @flow
|
||||
import * as tus from 'tus-js-client';
|
||||
import { makeUploadRequest } from './publish-v1';
|
||||
import { makeResumableUploadRequest } from './publish-v2';
|
||||
/*
|
||||
https://api.na-backend.odysee.com/api/v1/proxy currently expects publish to consist
|
||||
of a multipart/form-data POST request with:
|
||||
- 'file' binary
|
||||
- 'json_payload' collection of publish params to be passed to the server's sdk.
|
||||
*/
|
||||
import { X_LBRY_AUTH_TOKEN } from '../../ui/constants/token';
|
||||
import { doUpdateUploadProgress } from 'lbryinc';
|
||||
|
||||
// A modified version of Lbry.apiCall that allows
|
||||
// to perform calling methods at arbitrary urls
|
||||
// and pass form file fields
|
||||
export default function apiPublishCallViaWeb(
|
||||
apiCall: (any, any, any, any) => any,
|
||||
connectionString: string,
|
||||
token: string,
|
||||
method: string,
|
||||
params: FileUploadSdkParams,
|
||||
params: { file_path: string, preview: boolean, remote_url?: string }, // new param for remoteUrl
|
||||
resolve: Function,
|
||||
reject: Function
|
||||
) {
|
||||
|
@ -20,6 +26,7 @@ export default function apiPublishCallViaWeb(
|
|||
return apiCall(method, params, resolve, reject);
|
||||
}
|
||||
|
||||
const counter = new Date().getTime();
|
||||
let fileField = filePath;
|
||||
|
||||
if (preview) {
|
||||
|
@ -30,16 +37,53 @@ export default function apiPublishCallViaWeb(
|
|||
|
||||
// Putting a dummy value here, the server is going to process the POSTed file
|
||||
// and set the file_path itself
|
||||
|
||||
const body = new FormData();
|
||||
if (fileField) {
|
||||
body.append('file', fileField);
|
||||
params.file_path = '__POST_FILE__';
|
||||
delete params['remote_url'];
|
||||
} else if (remoteUrl) {
|
||||
body.append('remote_url', remoteUrl);
|
||||
delete params['remote_url'];
|
||||
}
|
||||
|
||||
const useV1 = remoteUrl || preview || !tus.isSupported;
|
||||
const jsonPayload = JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params,
|
||||
id: counter,
|
||||
});
|
||||
// no fileData? do the livestream remote publish
|
||||
body.append('json_payload', jsonPayload);
|
||||
|
||||
// Note: both function signature (params) should match.
|
||||
const makeRequest = useV1 ? makeUploadRequest : makeResumableUploadRequest;
|
||||
function makeRequest(connectionString, method, token, body, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open(method, connectionString);
|
||||
xhr.setRequestHeader(X_LBRY_AUTH_TOKEN, token);
|
||||
xhr.responseType = 'json';
|
||||
xhr.upload.onprogress = (e) => {
|
||||
let percentComplete = Math.ceil((e.loaded / e.total) * 100);
|
||||
window.store.dispatch(doUpdateUploadProgress(percentComplete, params, xhr));
|
||||
};
|
||||
xhr.onload = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
resolve(xhr);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
reject(new Error(__('There was a problem with your upload. Please try again.')));
|
||||
};
|
||||
|
||||
return makeRequest(token, params, fileField, preview)
|
||||
xhr.onabort = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
};
|
||||
xhr.send(body);
|
||||
});
|
||||
}
|
||||
|
||||
return makeRequest(connectionString, 'POST', token, body, params)
|
||||
.then((xhr) => {
|
||||
let error;
|
||||
if (xhr && xhr.response) {
|
||||
|
|
96
yarn.lock
96
yarn.lock
|
@ -3869,11 +3869,6 @@ buffer-fill@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
|
||||
buffer-from@^0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
|
||||
integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
|
@ -4639,14 +4634,6 @@ colors@~1.1.2:
|
|||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
|
||||
integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM=
|
||||
|
||||
combine-errors@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.3.tgz#f4df6740083e5703a3181110c2b10551f003da86"
|
||||
integrity sha1-9N9nQAg+VwOjGBEQwrEFUfAD2oY=
|
||||
dependencies:
|
||||
custom-error-instance "2.1.1"
|
||||
lodash.uniqby "4.5.0"
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
|
@ -5350,11 +5337,6 @@ currently-unhandled@^0.4.1:
|
|||
dependencies:
|
||||
array-find-index "^1.0.1"
|
||||
|
||||
custom-error-instance@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz#3cf6391487a6629a6247eb0ca0ce00081b7e361a"
|
||||
integrity sha1-PPY5FIemYppiR+sMoM4ACBt+Nho=
|
||||
|
||||
cyclist@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
||||
|
@ -9842,7 +9824,7 @@ jest@20.0.4:
|
|||
dependencies:
|
||||
jest-cli "^20.0.4"
|
||||
|
||||
js-base64@^2.1.9, js-base64@^2.6.1:
|
||||
js-base64@^2.1.9:
|
||||
version "2.6.4"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
||||
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
|
||||
|
@ -10393,48 +10375,11 @@ lodash-es@^4.17.14, lodash-es@^4.2.1:
|
|||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
|
||||
|
||||
lodash._baseiteratee@~4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz#34a9b5543572727c3db2e78edae3c0e9e66bd102"
|
||||
integrity sha1-NKm1VDVycnw9sueO2uPA6eZr0QI=
|
||||
dependencies:
|
||||
lodash._stringtopath "~4.8.0"
|
||||
|
||||
lodash._basetostring@~4.12.0:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz#9327c9dc5158866b7fa4b9d42f4638e5766dd9df"
|
||||
integrity sha1-kyfJ3FFYhmt/pLnUL0Y45XZt2d8=
|
||||
|
||||
lodash._baseuniq@~4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
||||
integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=
|
||||
dependencies:
|
||||
lodash._createset "~4.0.0"
|
||||
lodash._root "~3.0.0"
|
||||
|
||||
lodash._createset@~4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
||||
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
||||
|
||||
lodash._reinterpolate@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
|
||||
lodash._root@~3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
|
||||
integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
|
||||
|
||||
lodash._stringtopath@~4.8.0:
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz#941bcf0e64266e5fc1d66fed0a6959544c576824"
|
||||
integrity sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ=
|
||||
dependencies:
|
||||
lodash._basetostring "~4.12.0"
|
||||
|
||||
lodash.camelcase@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
|
@ -10504,11 +10449,6 @@ lodash.templatesettings@^4.0.0:
|
|||
dependencies:
|
||||
lodash._reinterpolate "^3.0.0"
|
||||
|
||||
lodash.throttle@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.toarray@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
||||
|
@ -10517,14 +10457,6 @@ lodash.uniq@^4.5.0:
|
|||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
||||
lodash.uniqby@4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz#a3a17bbf62eeb6240f491846e97c1c4e2a5e1e21"
|
||||
integrity sha1-o6F7v2LutiQPSRhG6XwcTipeHiE=
|
||||
dependencies:
|
||||
lodash._baseiteratee "~4.7.0"
|
||||
lodash._baseuniq "~4.6.0"
|
||||
|
||||
lodash.unset@^4.5.2:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.unset/-/lodash.unset-4.5.2.tgz#370d1d3e85b72a7e1b0cdf2d272121306f23e4ed"
|
||||
|
@ -13048,14 +12980,6 @@ prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0,
|
|||
object-assign "^4.1.1"
|
||||
react-is "^16.8.1"
|
||||
|
||||
proper-lockfile@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-2.0.1.tgz#159fb06193d32003f4b3691dd2ec1a634aa80d1d"
|
||||
integrity sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
retry "^0.10.0"
|
||||
|
||||
property-information@^5.3.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
|
||||
|
@ -14321,11 +14245,6 @@ ret@~0.1.10:
|
|||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
|
||||
retry@^0.10.0:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
|
||||
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
|
||||
|
||||
retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
|
@ -15977,19 +15896,6 @@ tunnel@^0.0.6:
|
|||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
||||
tus-js-client@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/tus-js-client/-/tus-js-client-2.3.0.tgz#5d76145476cea46a4e7c045a0054637cddf8dc39"
|
||||
integrity sha512-I4cSwm6N5qxqCmBqenvutwSHe9ntf81lLrtf6BmLpG2v4wTl89atCQKqGgqvkodE6Lx+iKIjMbaXmfvStTg01g==
|
||||
dependencies:
|
||||
buffer-from "^0.1.1"
|
||||
combine-errors "^3.0.3"
|
||||
is-stream "^2.0.0"
|
||||
js-base64 "^2.6.1"
|
||||
lodash.throttle "^4.1.1"
|
||||
proper-lockfile "^2.0.1"
|
||||
url-parse "^1.4.3"
|
||||
|
||||
tween-functions@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff"
|
||||
|
|
Loading…
Reference in a new issue