[merge after 34 release] Lbry redux publish WIP #2607

Merged
jessopb merged 5 commits from lbryReduxPublish into master 2019-07-29 20:51:10 +02:00
18 changed files with 61 additions and 503 deletions

View file

@ -124,7 +124,7 @@
"jsmediatags": "^3.8.1", "jsmediatags": "^3.8.1",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#ea56de4548480eb1a10b752b3cecbad7de2f8914", "lbry-redux": "lbryio/lbry-redux#8910693fe1fc4166fdc748d128344012c3d61874",
"lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb", "lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",

View file

@ -1,19 +1,18 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri, selectBalance } from 'lbry-redux';
import { import {
doResolveUri,
selectBalance,
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
selectMyClaimForUri, selectMyClaimForUri,
selectIsResolvingPublishUris, selectIsResolvingPublishUris,
selectTakeOverAmount, selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus, doResetThumbnailStatus,
doClearPublish, doClearPublish,
doUpdatePublishForm, doUpdatePublishForm,
doPublish,
doPrepareEdit, doPrepareEdit,
} from 'redux/actions/publish'; } from 'lbry-redux';
import { doPublishDesktop } from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view'; import PublishPage from './view';
@ -35,7 +34,7 @@ const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)), publish: () => dispatch(doPublishDesktop()),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)), prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()), resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
}); });

View file

@ -1,7 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance } from 'lbry-redux';
import { selectIsStillEditing, makeSelectPublishFormValue } from 'redux/selectors/publish'; import { selectBalance, selectIsStillEditing, makeSelectPublishFormValue, doUpdatePublishForm } from 'lbry-redux';
import { doUpdatePublishForm } from 'redux/actions/publish';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({

View file

@ -1,19 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri } from 'lbry-redux';
import { import {
doResolveUri,
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
selectMyClaimForUri, selectMyClaimForUri,
selectIsResolvingPublishUris, selectIsResolvingPublishUris,
selectTakeOverAmount, selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus, doResetThumbnailStatus,
doClearPublish, doClearPublish,
doUpdatePublishForm, doUpdatePublishForm,
doPublish,
doPrepareEdit, doPrepareEdit,
} from 'redux/actions/publish'; } from 'lbry-redux';
import { doPublishDesktop } from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view'; import PublishPage from './view';
@ -34,7 +32,7 @@ const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
neb-b commented 2019-07-09 17:51:45 +02:00 (Migrated from github.com)
Review

We don't need to pass in the callbacks here, lets do it in redux (in the desktop codebase).

We don't need to pass in the callbacks here, lets do it in redux (in the desktop codebase).
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)), publish: () => dispatch(doPublishDesktop()),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)), prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()), resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
}); });

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectPublishFormValue, selectIsStillEditing } from 'redux/selectors/publish'; import { makeSelectPublishFormValue, selectIsStillEditing } from 'lbry-redux';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({

View file

@ -5,9 +5,11 @@ import {
selectMyClaimForUri, selectMyClaimForUri,
selectIsResolvingPublishUris, selectIsResolvingPublishUris,
selectTakeOverAmount, selectTakeOverAmount,
} from 'redux/selectors/publish'; doUpdatePublishForm,
import { doUpdatePublishForm, doPrepareEdit } from 'redux/actions/publish'; doPrepareEdit,
import { selectBalance } from 'lbry-redux'; selectBalance,
} from 'lbry-redux';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({
@ -15,7 +17,6 @@ const select = state => ({
channel: makeSelectPublishFormValue('channel')(state), channel: makeSelectPublishFormValue('channel')(state),
bid: makeSelectPublishFormValue('bid')(state), bid: makeSelectPublishFormValue('bid')(state),
uri: makeSelectPublishFormValue('uri')(state), uri: makeSelectPublishFormValue('uri')(state),
bid: makeSelectPublishFormValue('bid')(state),
isStillEditing: selectIsStillEditing(state), isStillEditing: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state), isResolvingUri: selectIsResolvingPublishUris(state),
amountNeededForTakeover: selectTakeOverAmount(state), amountNeededForTakeover: selectTakeOverAmount(state),

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doUpdatePublishForm } from 'redux/actions/publish'; import { makeSelectPublishFormValue, doUpdatePublishForm } from 'lbry-redux';
import { makeSelectPublishFormValue } from 'redux/selectors/publish';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectPublishFormValue } from 'redux/selectors/publish'; import { doUpdatePublishForm, makeSelectPublishFormValue } from 'lbry-redux';
import { doUpdatePublishForm } from 'redux/actions/publish';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({

View file

@ -1,20 +1,19 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri } from 'lbry-redux';
import { import {
doResolveUri,
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
selectMyClaimForUri, selectMyClaimForUri,
selectIsResolvingPublishUris, selectIsResolvingPublishUris,
selectTakeOverAmount, selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus, doResetThumbnailStatus,
doClearPublish, doClearPublish,
doUpdatePublishForm, doUpdatePublishForm,
doPublish,
doPrepareEdit, doPrepareEdit,
} from 'redux/actions/publish'; } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { doPublishDesktop } from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view'; import PublishPage from './view';
@ -35,7 +34,7 @@ const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)), publish: () => dispatch(doPublishDesktop()),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)), prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()), resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),

View file

@ -1,7 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { doUploadThumbnail } from 'redux/actions/publish'; import { doToast, doUploadThumbnail } from 'lbry-redux';
import { doToast } from 'lbry-redux';
import ModalAutoGenerateThumbnail from './view'; import ModalAutoGenerateThumbnail from './view';
const perform = dispatch => ({ const perform = dispatch => ({

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { doUploadThumbnail, doUpdatePublishForm } from 'redux/actions/publish'; import { doUploadThumbnail, doUpdatePublishForm } from 'lbry-redux';
import ModalConfirmThumbnailUpload from './view'; import ModalConfirmThumbnailUpload from './view';
const perform = dispatch => ({ const perform = dispatch => ({

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import ModalPublishSuccess from './view'; import ModalPublishSuccess from './view';
import { doClearPublish } from 'redux/actions/publish'; import { doClearPublish } from 'lbry-redux';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
const perform = dispatch => ({ const perform = dispatch => ({

View file

@ -16,11 +16,11 @@ import {
makeSelectTitleForUri, makeSelectTitleForUri,
makeSelectThumbnailForUri, makeSelectThumbnailForUri,
makeSelectClaimIsNsfw, makeSelectClaimIsNsfw,
doPrepareEdit,
} from 'lbry-redux'; } from 'lbry-redux';
import { doFetchViewCount, makeSelectViewCountForUri, makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc'; import { doFetchViewCount, makeSelectViewCountForUri, makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings'; import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
import { doPrepareEdit } from 'redux/actions/publish';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import FilePage from './view'; import FilePage from './view';

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectIsFetchingClaimListMine, selectMyClaimUrisWithoutChannels } from 'lbry-redux'; import { selectIsFetchingClaimListMine, selectMyClaimUrisWithoutChannels } from 'lbry-redux';
import { doCheckPendingPublishes } from 'redux/actions/publish'; import { doCheckPendingPublishesApp } from 'redux/actions/publish';
import FileListPublished from './view'; import FileListPublished from './view';
const select = state => ({ const select = state => ({
@ -9,7 +9,7 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
checkPendingPublishes: () => dispatch(doCheckPendingPublishes()), checkPendingPublishes: () => dispatch(doCheckPendingPublishesApp()),
}); });
export default connect( export default connect(

View file

@ -8,6 +8,7 @@ import {
notificationsReducer, notificationsReducer,
tagsReducer, tagsReducer,
commentReducer, commentReducer,
publishReducer,
} from 'lbry-redux'; } from 'lbry-redux';
import { import {
userReducer, userReducer,
@ -23,7 +24,7 @@ import availabilityReducer from 'redux/reducers/availability';
import contentReducer from 'redux/reducers/content'; import contentReducer from 'redux/reducers/content';
import settingsReducer from 'redux/reducers/settings'; import settingsReducer from 'redux/reducers/settings';
import subscriptionsReducer from 'redux/reducers/subscriptions'; import subscriptionsReducer from 'redux/reducers/subscriptions';
import publishReducer from 'redux/reducers/publish';
export default history => export default history =>
combineReducers({ combineReducers({

View file

@ -1,319 +1,25 @@
// @flow // @flow
import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/licenses';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { import { batchActions, doError, selectMyClaims, doPublish, doCheckPendingPublishes } from 'lbry-redux';
ACTIONS, import * as ACTIONS from 'constants/action_types';
Lbry,
selectMyChannelClaims,
THUMBNAIL_STATUSES,
batchActions,
creditsToString,
selectPendingById,
selectMyClaimsWithoutChannels,
doError,
isClaimNsfw,
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectosNotificationsEnabled } from 'redux/selectors/settings'; import { selectosNotificationsEnabled } from 'redux/selectors/settings';
import { selectMyClaimForUri, selectPublishFormValues } from 'redux/selectors/publish';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import analytics from 'analytics'; import analytics from 'analytics';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
// @if TARGET='app' import { doOpenModal } from './app';
import fs from 'fs';
import path from 'path';
// @endif
export const doResetThumbnailStatus = () => (dispatch: Dispatch) => { export const doPublishDesktop = () => (dispatch: Dispatch, getState: () => {}) => {
dispatch({ const publishSuccess = successResponse => {
type: ACTIONS.UPDATE_PUBLISH_FORM, const state = getState();
data: {
thumbnailPath: '',
},
});
return fetch('https://spee.ch/api/config/site/publishing')
.then(res => res.json())
.then(status => {
if (status.disabled) {
throw Error();
}
return dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.READY,
thumbnail: '',
},
});
})
.catch(() =>
dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN,
thumbnail: '',
},
})
);
};
export const doClearPublish = () => (dispatch: Dispatch) => {
dispatch({ type: ACTIONS.CLEAR_PUBLISH });
return dispatch(doResetThumbnailStatus());
};
export const doUpdatePublishForm = (publishFormValue: UpdatePublishFormData) => (dispatch: Dispatch) =>
dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: { ...publishFormValue },
});
export const doUploadThumbnail = (filePath: string, thumbnailBuffer: Uint8Array) => (dispatch: Dispatch) => {
let thumbnail, fileExt, fileName, fileType;
if (filePath) {
thumbnail = fs.readFileSync(filePath);
fileExt = path.extname(filePath);
fileName = path.basename(filePath);
fileType = `image/${fileExt.slice(1)}`;
} else if (thumbnailBuffer) {
thumbnail = thumbnailBuffer;
fileExt = '.png';
fileName = 'thumbnail.png';
fileType = 'image/png';
} else {
return null;
}
const makeid = () => {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 24; i += 1) text += possible.charAt(Math.floor(Math.random() * 62));
return text;
};
const uploadError = (error = '') =>
dispatch(
batchActions(
{
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.READY,
thumbnail: '',
nsfw: false,
},
},
doError(error)
)
);
dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: { uploadThumbnailStatus: THUMBNAIL_STATUSES.IN_PROGRESS },
});
const data = new FormData();
const name = makeid();
const file = new File([thumbnail], fileName, { type: fileType });
data.append('name', name);
data.append('file', file);
return fetch('https://spee.ch/api/claim/publish', {
method: 'POST',
body: data,
})
.then(response => response.json())
.then(json =>
json.success
? dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError(json.message)
)
.catch(err => uploadError(err.message));
};
export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileListItem) => (dispatch: Dispatch) => {
const { name, amount, value } = claim;
const channelName = (claim && claim.signing_channel && claim.signing_channel.normalized_name) || null;
const {
author,
description,
// use same values as default state
// fee will be undefined for free content
fee = {
amount: '0',
currency: 'LBC',
},
languages,
license,
license_url: licenseUrl,
thumbnail,
title,
tags,
} = value;
const publishData: UpdatePublishFormData = {
name,
bid: Number(amount),
contentIsFree: fee.amount === '0',
author,
description,
fee,
languages,
thumbnail: thumbnail ? thumbnail.url : null,
title,
uri,
uploadThumbnailStatus: thumbnail ? THUMBNAIL_STATUSES.MANUAL : undefined,
licenseUrl,
nsfw: isClaimNsfw(claim),
tags: tags ? tags.map(tag => ({ name: tag })) : [],
};
if (channelName) {
publishData['channel'] = channelName;
}
// Make sure custom liscence's are mapped properly
// If the license isn't one of the standard licenses, map the custom license and description/url
if (!CC_LICENSES.some(({ value }) => value === license)) {
if (!license || license === NONE || license === PUBLIC_DOMAIN) {
publishData.licenseType = license;
} else if (license && !licenseUrl && license !== NONE) {
publishData.licenseType = COPYRIGHT;
} else {
publishData.licenseType = OTHER;
}
publishData.otherLicenseDescription = license;
} else {
publishData.licenseType = license;
}
if (fileInfo && fileInfo.download_path) {
try {
fs.accessSync(fileInfo.download_path, fs.constants.R_OK);
publishData.filePath = fileInfo.download_path;
} catch (e) {
console.error(e.name, e.message); // eslint-disable-line no-console
}
}
dispatch({ type: ACTIONS.DO_PREPARE_EDIT, data: publishData });
};
export const doPublish = () => (dispatch: Dispatch, getState: () => {}) => {
dispatch({ type: ACTIONS.PUBLISH_START });
const state = getState();
const publishData = selectPublishFormValues(state);
const myClaimForUri = selectMyClaimForUri(state);
const myChannels = selectMyChannelClaims(state);
const myClaims = selectMyClaimsWithoutChannels(state);
const {
name,
bid,
filePath,
description,
language,
licenseUrl,
licenseType,
otherLicenseDescription,
thumbnail,
channel,
title,
contentIsFree,
fee,
uri,
tags,
locations,
} = publishData;
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.find(myChannel => myChannel.name === channel);
const channelId = namedChannelClaim ? namedChannelClaim.claim_id : '';
const publishPayload: {
name: ?string,
channel_id?: string,
bid: number,
file_path?: string,
tags: Array<string>,
locations?: Array<Location>,
license_url?: string,
license?: string,
thumbnail_url?: string,
release_time?: number,
fee_currency?: string,
fee_amount?: string,
} = {
name,
title,
description,
locations,
bid: creditsToString(bid),
languages: [language],
tags: tags && tags.map(tag => tag.name),
thumbnail_url: thumbnail,
};
if (publishingLicense) {
publishPayload.license = publishingLicense;
}
if (licenseUrl) {
publishPayload.license_url = licenseUrl;
}
// Set release time to curret date. On edits, keep original release/transaction time as release_time
if (myClaimForUri && myClaimForUri.value.release_time) {
publishPayload.release_time = Number(myClaimForUri.value.release_time);
} else if (myClaimForUri && myClaimForUri.timestamp) {
publishPayload.release_time = Number(myClaimForUri.timestamp);
} else {
publishPayload.release_time = Number(Math.round(Date.now() / 1000));
}
if (channelId) {
publishPayload.channel_id = channelId;
}
if (!contentIsFree && fee && (fee.currency && Number(fee.amount) > 0)) {
publishPayload.fee_currency = fee.currency;
publishPayload.fee_amount = creditsToString(fee.amount);
}
// Only pass file on new uploads, not metadata only edits.
// The sdk will figure it out
if (filePath) publishPayload.file_path = filePath;
const success = successResponse => {
analytics.apiLogPublish(); analytics.apiLogPublish();
const myClaims = selectMyClaims(state);
const pendingClaim = successResponse.outputs[0]; const pendingClaim = successResponse.outputs[0];
const uri = pendingClaim.permanent_url;
const actions = []; const actions = [];
actions.push({ actions.push({
type: ACTIONS.PUBLISH_SUCCESS, type: ACTIONS.PUBLISH_SUCCESS,
}); });
// We have to fake a temp claim until the new pending one is returned by claim_list_mine // 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 // 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 // Doing this allows us to show the pending claim immediately, it will get overwritten by the real one
@ -323,74 +29,38 @@ export const doPublish = () => (dispatch: Dispatch, getState: () => {}) => {
const myNewClaims = isEdit const myNewClaims = isEdit
? myClaims.map(claim => (isMatch(claim) ? pendingClaim : claim)) ? myClaims.map(claim => (isMatch(claim) ? pendingClaim : claim))
: myClaims.concat(pendingClaim); : myClaims.concat(pendingClaim);
actions.push(doOpenModal(MODALS.PUBLISH, { uri, isEdit })); actions.push(doOpenModal(MODALS.PUBLISH, { uri, isEdit }));
actions.push({ actions.push({
type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED, type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED,
data: { data: {
claims: myNewClaims, claims: myNewClaims,
}, },
}); });
dispatch(batchActions(...actions)); dispatch(batchActions(...actions));
}; };
const failure = error => { const publishFail = error => {
dispatch({ type: ACTIONS.PUBLISH_FAIL }); const actions = [];
dispatch(doError(error.message)); actions.push({ type: ACTIONS.PUBLISH_FAIL });
actions.push(doError(error.message));
dispatch(batchActions(...actions));
}; };
return Lbry.publish(publishPayload).then(success, failure); return dispatch(doPublish(publishSuccess, publishFail));
}; };
// Calls claim_list_mine until any pending publishes are confirmed // Calls claim_list_mine until any pending publishes are confirmed
export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetState) => { export const doCheckPendingPublishesApp = () => (dispatch: Dispatch, getState: GetState) => {
const state = getState(); const onConfirmed = claim => {
const pendingById = selectPendingById(state); if (selectosNotificationsEnabled(getState())) {
const notif = new window.Notification('LBRY Publish Complete', {
if (!Object.keys(pendingById).length) { body: `${claim.value.title} has been published to lbry://${claim.name}. Click here to view it`,
return; silent: false,
}
let publishCheckInterval;
const checkFileList = () => {
Lbry.claim_list().then(claims => {
if (claims) {
claims.forEach(claim => {
// If it's confirmed, check if it was pending previously
if (claim.confirmations > 0 && pendingById[claim.claim_id]) {
delete pendingById[claim.claim_id];
// If it's confirmed, check if we should notify the user
if (selectosNotificationsEnabled(getState())) {
const notif = new window.Notification('LBRY Publish Complete', {
body: `${claim.value.title} has been published to lbry://${claim.name}. Click here to view it`,
silent: false,
});
notif.onclick = () => {
dispatch(push(formatLbryUriForWeb(claim.permanent_url)));
};
}
}
});
}
dispatch({
type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED,
data: {
claims,
},
}); });
notif.onclick = () => {
if (!Object.keys(pendingById).length) { dispatch(push(formatLbryUriForWeb(claim.permanent_url)));
clearInterval(publishCheckInterval); };
} }
});
}; };
return dispatch(doCheckPendingPublishes(onConfirmed));
publishCheckInterval = setInterval(() => {
checkFileList();
}, 30000);
}; };

View file

@ -1,107 +1 @@
// @flow // deleted, moved to lbry-redux
import { handleActions } from 'util/redux-utils';
import { buildURI } from 'lbry-redux';
import * as ACTIONS from 'constants/action_types';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import { CHANNEL_ANONYMOUS } from 'constants/claim';
type PublishState = {
editingURI: ?string,
filePath: ?string,
contentIsFree: boolean,
fee: {
amount: number,
currency: string,
},
title: string,
thumbnail_url: string,
thumbnailPath: string,
uploadThumbnailStatus: string,
description: string,
language: string,
channel: string,
channelId: ?string,
name: string,
nameError: ?string,
bid: number,
bidError: ?string,
otherLicenseDescription: string,
licenseUrl: string,
tags: Array<string>,
};
const defaultState: PublishState = {
editingURI: undefined,
filePath: undefined,
contentIsFree: true,
fee: {
amount: 1,
currency: 'LBC',
},
title: '',
thumbnail_url: '',
thumbnailPath: '',
uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN,
description: '',
language: 'en',
nsfw: false,
channel: CHANNEL_ANONYMOUS,
channelId: '',
name: '',
nameError: undefined,
bid: 0.1,
bidError: undefined,
licenseType: 'None',
otherLicenseDescription: 'All rights reserved',
licenseUrl: '',
tags: [],
publishing: false,
publishSuccess: false,
publishError: undefined,
};
export default handleActions(
{
[ACTIONS.UPDATE_PUBLISH_FORM]: (state, action): PublishState => {
const { data } = action;
return {
...state,
...data,
};
},
[ACTIONS.CLEAR_PUBLISH]: (): PublishState => ({
...defaultState,
}),
[ACTIONS.PUBLISH_START]: (state: PublishState): PublishState => ({
...state,
publishing: true,
}),
[ACTIONS.PUBLISH_FAIL]: (state: PublishState): PublishState => ({
...state,
publishing: false,
}),
[ACTIONS.PUBLISH_SUCCESS]: (state: PublishState): PublishState => ({
...state,
publishing: false,
}),
[ACTIONS.DO_PREPARE_EDIT]: (state: PublishState, action) => {
const { ...publishData } = action.data;
const { channel, name, uri } = publishData;
// The short uri is what is presented to the user
// The editingUri is the full uri with claim id
const shortUri = buildURI({
channelName: channel,
contentName: name,
});
return {
...defaultState,
...publishData,
editingURI: uri,
uri: shortUri,
};
},
},
defaultState
);

View file

@ -6653,9 +6653,9 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2" yargs "^13.2.2"
zstd-codec "^0.1.1" zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#ea56de4548480eb1a10b752b3cecbad7de2f8914: lbry-redux@lbryio/lbry-redux#8910693fe1fc4166fdc748d128344012c3d61874:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/ea56de4548480eb1a10b752b3cecbad7de2f8914" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/8910693fe1fc4166fdc748d128344012c3d61874"
dependencies: dependencies:
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"
reselect "^3.0.0" reselect "^3.0.0"