Compare commits

..

27 commits

Author SHA1 Message Date
zeppi
0f930c4a7b sync-language 2021-10-08 16:12:32 -04:00
zeppi
32b5787071 pass channel_id on list update 2021-09-13 12:05:57 -04:00
Thomas Zarebczan
129b0ea3fa
Merge pull request #431 from saltrafael/list-thumb
Changes for list thumbnail upload
2021-09-13 11:24:58 -04:00
saltrafael
e3bc848263
Add cb to thumbnail upload 2021-09-13 07:38:21 -03:00
zeppi
372e559cae use replace for list updates 2021-09-11 13:18:41 -04:00
saltrafael
49b9db5aae Fix autoplay not saving 2021-09-06 13:17:07 -04:00
Thomas Zarebczan
12a2ffc708
Merge pull request #426 from saltrafael/playback-controls
Playback and List control changes
2021-09-01 14:08:36 -04:00
Thomas Zarebczan
95fa26f836
Merge pull request #428 from lbryio/ip/from.entries.poly
Fix Object.fromEntries crash on some browsers
2021-09-01 12:04:46 -04:00
infiinte-persistence
dc264ec50c
Fix Object.fromEntries crash on some browsers
## Issue
6985 fromentries app crash - fix or add polyfill
2021-09-01 10:20:40 +08:00
saltrafael
aeb1f533b5
Playback and List control changes 2021-08-25 09:01:50 -03:00
zeppi
d016d8057b cleanup 2021-08-23 10:20:22 -04:00
zeppi
0302a2f8d6 fix background collection update 2021-08-23 10:20:22 -04:00
zeppi
8fa92d872d add isBackgroundUpdate to collection update 2021-08-23 10:20:22 -04:00
zeppi
e4d0662100 build 2021-08-06 12:33:10 -04:00
zeppi
036aa59086 fix collection edit 2021-08-06 12:33:10 -04:00
Thomas Zarebczan
c76dfbde27
Merge pull request #423 from lbryio/playlist-fetch-changes
change collection fetch params
2021-08-03 14:18:20 -04:00
zeppi
7cc9923ed9 change collection fetch params 2021-08-03 14:05:03 -04:00
zeppi
60bd918d5e U_S_P edited collection
bugfix

sync edited
2021-08-02 09:45:43 -04:00
saltrafael
9ebfc927d0 Change rLists selector 2021-07-30 11:01:18 -04:00
saltrafael
54ca8c4320 Filter rLists 2021-07-30 11:01:18 -04:00
saltrafael
bee9bf38dd Add claim in collections selector 2021-07-30 11:01:18 -04:00
infiinte-persistence
aabae5ce59
Add custom comments-server settings
## Issue
5459: Add setting for changing your comment server. Visible on desktop (and possibly defaulting to Odysee URL), hidden on odysee.
2021-07-25 20:52:22 +08:00
zeppi
a327385cdf clean 2021-07-15 17:14:28 -04:00
zeppi
64ce7aa99c handle colons maybe 2021-07-15 17:14:28 -04:00
zeppi
34dfd384e4 logging 2021-07-15 17:14:28 -04:00
zeppi
707c60b813 parse either claimId separator 2021-07-15 17:14:28 -04:00
zeppi
8f66a2fe7c fix pending ids selector 2021-07-05 15:57:47 -04:00
16 changed files with 384 additions and 108 deletions

189
dist/bundle.es.js vendored
View file

@ -2,9 +2,12 @@
Object.defineProperty(exports, '__esModule', { value: true }); Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
require('proxy-polyfill'); require('proxy-polyfill');
var uuid = require('uuid'); var uuid = require('uuid');
var reselect = require('reselect'); var reselect = require('reselect');
var fromEntries = _interopDefault(require('@ungap/from-entries'));
const MINIMUM_PUBLISH_BID = 0.00000001; const MINIMUM_PUBLISH_BID = 0.00000001;
@ -716,7 +719,7 @@ const INSTANT_PURCHASE_MAX = 'instant_purchase_max';
const THEME = 'theme'; const THEME = 'theme';
const THEMES = 'themes'; const THEMES = 'themes';
const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled'; const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled';
const AUTOPLAY = 'autoplay'; const AUTOPLAY_MEDIA = 'autoplay';
const AUTOPLAY_NEXT = 'autoplay_next'; const AUTOPLAY_NEXT = 'autoplay_next';
const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled'; const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled';
const AUTO_DOWNLOAD = 'auto_download'; const AUTO_DOWNLOAD = 'auto_download';
@ -732,6 +735,8 @@ const ENABLE_PUBLISH_PREVIEW = 'enable-publish-preview';
const TILE_LAYOUT = 'tile_layout'; const TILE_LAYOUT = 'tile_layout';
const VIDEO_THEATER_MODE = 'video_theater_mode'; const VIDEO_THEATER_MODE = 'video_theater_mode';
const VIDEO_PLAYBACK_RATE = 'video_playback_rate'; const VIDEO_PLAYBACK_RATE = 'video_playback_rate';
const CUSTOM_COMMENTS_SERVER_ENABLED = 'custom_comments_server_enabled';
const CUSTOM_COMMENTS_SERVER_URL = 'custom_comments_server_url';
// mobile settings // mobile settings
const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled'; const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled';
@ -765,7 +770,7 @@ var settings = /*#__PURE__*/Object.freeze({
THEME: THEME, THEME: THEME,
THEMES: THEMES, THEMES: THEMES,
AUTOMATIC_DARK_MODE_ENABLED: AUTOMATIC_DARK_MODE_ENABLED, AUTOMATIC_DARK_MODE_ENABLED: AUTOMATIC_DARK_MODE_ENABLED,
AUTOPLAY: AUTOPLAY, AUTOPLAY_MEDIA: AUTOPLAY_MEDIA,
AUTOPLAY_NEXT: AUTOPLAY_NEXT, AUTOPLAY_NEXT: AUTOPLAY_NEXT,
OS_NOTIFICATIONS_ENABLED: OS_NOTIFICATIONS_ENABLED, OS_NOTIFICATIONS_ENABLED: OS_NOTIFICATIONS_ENABLED,
AUTO_DOWNLOAD: AUTO_DOWNLOAD, AUTO_DOWNLOAD: AUTO_DOWNLOAD,
@ -781,6 +786,8 @@ var settings = /*#__PURE__*/Object.freeze({
TILE_LAYOUT: TILE_LAYOUT, TILE_LAYOUT: TILE_LAYOUT,
VIDEO_THEATER_MODE: VIDEO_THEATER_MODE, VIDEO_THEATER_MODE: VIDEO_THEATER_MODE,
VIDEO_PLAYBACK_RATE: VIDEO_PLAYBACK_RATE, VIDEO_PLAYBACK_RATE: VIDEO_PLAYBACK_RATE,
CUSTOM_COMMENTS_SERVER_ENABLED: CUSTOM_COMMENTS_SERVER_ENABLED,
CUSTOM_COMMENTS_SERVER_URL: CUSTOM_COMMENTS_SERVER_URL,
BACKGROUND_PLAY_ENABLED: BACKGROUND_PLAY_ENABLED, BACKGROUND_PLAY_ENABLED: BACKGROUND_PLAY_ENABLED,
FOREGROUND_NOTIFICATION_ENABLED: FOREGROUND_NOTIFICATION_ENABLED, FOREGROUND_NOTIFICATION_ENABLED: FOREGROUND_NOTIFICATION_ENABLED,
KEEP_DAEMON_RUNNING: KEEP_DAEMON_RUNNING, KEEP_DAEMON_RUNNING: KEEP_DAEMON_RUNNING,
@ -1033,7 +1040,7 @@ var daemon_settings = /*#__PURE__*/Object.freeze({
const SDK_SYNC_KEYS = [LBRYUM_SERVERS, SHARE_USAGE_DATA]; const SDK_SYNC_KEYS = [LBRYUM_SERVERS, SHARE_USAGE_DATA];
// CLIENT // CLIENT
const CLIENT_SYNC_KEYS = [SHOW_MATURE, HIDE_REPOSTS, SHOW_ANONYMOUS, INSTANT_PURCHASE_ENABLED, INSTANT_PURCHASE_MAX, THEME, AUTOPLAY, HIDE_BALANCE, HIDE_SPLASH_ANIMATION, FLOATING_PLAYER, DARK_MODE_TIMES, AUTOMATIC_DARK_MODE_ENABLED]; const CLIENT_SYNC_KEYS = [SHOW_MATURE, HIDE_REPOSTS, SHOW_ANONYMOUS, INSTANT_PURCHASE_ENABLED, INSTANT_PURCHASE_MAX, THEME, AUTOPLAY_MEDIA, AUTOPLAY_NEXT, HIDE_BALANCE, HIDE_SPLASH_ANIMATION, FLOATING_PLAYER, DARK_MODE_TIMES, AUTOMATIC_DARK_MODE_ENABLED, LANGUAGE];
var shared_preferences = /*#__PURE__*/Object.freeze({ var shared_preferences = /*#__PURE__*/Object.freeze({
SDK_SYNC_KEYS: SDK_SYNC_KEYS, SDK_SYNC_KEYS: SDK_SYNC_KEYS,
@ -1473,7 +1480,7 @@ const channelNameMinLength = 1;
const claimIdMaxLength = 40; const claimIdMaxLength = 40;
// see https://spec.lbry.com/#urls // see https://spec.lbry.com/#urls
const regexInvalidURI = /[ =&#:$@%?;/\\"<>%\{\}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u; const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
const regexPartProtocol = '^((?:lbry://)?)'; const regexPartProtocol = '^((?:lbry://)?)';
const regexPartStreamOrChannelName = '([^:$#/]*)'; const regexPartStreamOrChannelName = '([^:$#/]*)';
@ -1481,6 +1488,11 @@ const regexPartModifierSeparator = '([:$#]?)([^/]*)';
const queryStringBreaker = '^([\\S]+)([?][\\S]*)'; const queryStringBreaker = '^([\\S]+)([?][\\S]*)';
const separateQuerystring = new RegExp(queryStringBreaker); const separateQuerystring = new RegExp(queryStringBreaker);
const MOD_SEQUENCE_SEPARATOR = '*';
const MOD_CLAIM_ID_SEPARATOR_OLD = '#';
const MOD_CLAIM_ID_SEPARATOR = ':';
const MOD_BID_POSITION_SEPARATOR = '$';
/** /**
* Parses a LBRY name into its component parts. Throws errors with user-friendly * Parses a LBRY name into its component parts. Throws errors with user-friendly
* messages for invalid names. * messages for invalid names.
@ -1582,11 +1594,11 @@ function parseURIModifier(modSeperator, modValue) {
throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator }));
} }
if (modSeperator === '#') { if (modSeperator === MOD_CLAIM_ID_SEPARATOR || MOD_CLAIM_ID_SEPARATOR_OLD) {
claimId = modValue; claimId = modValue;
} else if (modSeperator === ':') { } else if (modSeperator === MOD_SEQUENCE_SEPARATOR) {
claimSequence = modValue; claimSequence = modValue;
} else if (modSeperator === '$') { } else if (modSeperator === MOD_BID_POSITION_SEPARATOR) {
bidPosition = modValue; bidPosition = modValue;
} }
} }
@ -1717,6 +1729,25 @@ function convertToShareLink(URL) {
}, true, 'https://open.lbry.com/'); }, true, 'https://open.lbry.com/');
} }
function splitBySeparator(uri) {
const protocolLength = 7;
return uri.startsWith('lbry://') ? uri.slice(protocolLength).split(/[#:*]/) : uri.split(/#:\*\$/);
}
function isURIEqual(uriA, uriB) {
const parseA = parseURI(normalizeURI(uriA));
const parseB = parseURI(normalizeURI(uriB));
if (parseA.isChannel) {
if (parseB.isChannel && parseA.channelClaimId === parseB.channelClaimId) {
return true;
}
} else if (parseA.streamClaimId === parseB.streamClaimId) {
return true;
} else {
return false;
}
}
/* eslint-disable */ /* eslint-disable */
// underscore's deep equal function // underscore's deep equal function
// https://github.com/jashkenas/underscore/blob/master/underscore.js#L1189 // https://github.com/jashkenas/underscore/blob/master/underscore.js#L1189
@ -1840,11 +1871,12 @@ function extractUserState(rawObj) {
app_welcome_version, app_welcome_version,
sharing_3P, sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections savedCollections
} = rawObj.value; } = rawObj.value;
return _extends$1({}, subscriptions ? { subscriptions } : {}, following ? { following } : {}, tags ? { tags } : {}, blocked ? { blocked } : {}, coin_swap_codes ? { coin_swap_codes } : {}, settings ? { settings } : {}, app_welcome_version ? { app_welcome_version } : {}, sharing_3P ? { sharing_3P } : {}, unpublishedCollections ? { unpublishedCollections } : {}, builtinCollections ? { builtinCollections } : {}, savedCollections ? { savedCollections } : {}); return _extends$1({}, subscriptions ? { subscriptions } : {}, following ? { following } : {}, tags ? { tags } : {}, blocked ? { blocked } : {}, coin_swap_codes ? { coin_swap_codes } : {}, settings ? { settings } : {}, app_welcome_version ? { app_welcome_version } : {}, sharing_3P ? { sharing_3P } : {}, unpublishedCollections ? { unpublishedCollections } : {}, editedCollections ? { editedCollections } : {}, builtinCollections ? { builtinCollections } : {}, savedCollections ? { savedCollections } : {});
} }
return {}; return {};
@ -1862,6 +1894,7 @@ function doPopulateSharedUserState(sharedSettings) {
app_welcome_version, app_welcome_version,
sharing_3P, sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections savedCollections
} = extractUserState(sharedSettings); } = extractUserState(sharedSettings);
@ -1877,6 +1910,7 @@ function doPopulateSharedUserState(sharedSettings) {
welcomeVersion: app_welcome_version, welcomeVersion: app_welcome_version,
allowAnalytics: sharing_3P, allowAnalytics: sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections savedCollections
} }
@ -2461,7 +2495,7 @@ const makeSelectClaimForUri = (uri, returnRepost = true) => reselect.createSelec
const channelUrl = claim.signing_channel && (claim.signing_channel.canonical_url || claim.signing_channel.permanent_url); const channelUrl = claim.signing_channel && (claim.signing_channel.canonical_url || claim.signing_channel.permanent_url);
return _extends$3({}, repostedClaim, { return _extends$3({}, repostedClaim, {
repost_url: uri, repost_url: normalizeURI(uri),
repost_channel_url: channelUrl, repost_channel_url: channelUrl,
repost_bid_amount: claim && claim.meta && claim.meta.effective_amount repost_bid_amount: claim && claim.meta && claim.meta.effective_amount
}); });
@ -2712,9 +2746,9 @@ const makeSelectPendingClaimForUri = uri => reselect.createSelector(selectPendin
return matchingClaim || null; return matchingClaim || null;
}); });
const makeSelectTotalItemsForChannel = uri => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri]); const makeSelectTotalItemsForChannel = uri => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[normalizeURI(uri)]);
const makeSelectTotalPagesForChannel = (uri, pageSize = 10) => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri] && Math.ceil(byUri[uri] / pageSize)); const makeSelectTotalPagesForChannel = (uri, pageSize = 10) => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri] && Math.ceil(byUri[normalizeURI(uri)] / pageSize));
const makeSelectNsfwCountFromUris = uris => reselect.createSelector(selectClaimsByUri, claims => uris.reduce((acc, uri) => { const makeSelectNsfwCountFromUris = uris => reselect.createSelector(selectClaimsByUri, claims => uris.reduce((acc, uri) => {
const claim = claims[uri]; const claim = claims[uri];
@ -3617,7 +3651,7 @@ const makeSelectCollectionIsMine = id => reselect.createSelector(selectMyCollect
const selectMyPublishedCollections = reselect.createSelector(selectResolvedCollections, selectPendingCollections, selectMyEditedCollections, selectMyCollectionIds, (resolved, pending, edited, myIds) => { const selectMyPublishedCollections = reselect.createSelector(selectResolvedCollections, selectPendingCollections, selectMyEditedCollections, selectMyCollectionIds, (resolved, pending, edited, myIds) => {
// all resolved in myIds, plus those in pending and edited // all resolved in myIds, plus those in pending and edited
const myPublishedCollections = Object.fromEntries(Object.entries(pending).concat(Object.entries(resolved).filter(([key, val]) => myIds.includes(key) && const myPublishedCollections = fromEntries(Object.entries(pending).concat(Object.entries(resolved).filter(([key, val]) => myIds.includes(key) &&
// $FlowFixMe // $FlowFixMe
!pending[key]))); !pending[key])));
// now add in edited: // now add in edited:
@ -3628,7 +3662,7 @@ const selectMyPublishedCollections = reselect.createSelector(selectResolvedColle
}); });
const selectMyPublishedMixedCollections = reselect.createSelector(selectMyPublishedCollections, published => { const selectMyPublishedMixedCollections = reselect.createSelector(selectMyPublishedCollections, published => {
const myCollections = Object.fromEntries( const myCollections = fromEntries(
// $FlowFixMe // $FlowFixMe
Object.entries(published).filter(([key, collection]) => { Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe // $FlowFixMe
@ -3638,7 +3672,7 @@ const selectMyPublishedMixedCollections = reselect.createSelector(selectMyPublis
}); });
const selectMyPublishedPlaylistCollections = reselect.createSelector(selectMyPublishedCollections, published => { const selectMyPublishedPlaylistCollections = reselect.createSelector(selectMyPublishedCollections, published => {
const myCollections = Object.fromEntries( const myCollections = fromEntries(
// $FlowFixMe // $FlowFixMe
Object.entries(published).filter(([key, collection]) => { Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe // $FlowFixMe
@ -3653,7 +3687,7 @@ const makeSelectMyPublishedCollectionForId = id => reselect.createSelector(selec
// selectResolvedCollections, // selectResolvedCollections,
// selectSavedCollectionIds, // selectSavedCollectionIds,
// (resolved, myIds) => { // (resolved, myIds) => {
// const mySavedCollections = Object.fromEntries( // const mySavedCollections = fromEntries(
// Object.entries(resolved).filter(([key, val]) => myIds.includes(key)) // Object.entries(resolved).filter(([key, val]) => myIds.includes(key))
// ); // );
// return mySavedCollections; // return mySavedCollections;
@ -3669,6 +3703,20 @@ const makeSelectCollectionForId = id => reselect.createSelector(selectBuiltinCol
return collection; return collection;
}); });
const makeSelectClaimUrlInCollection = url => reselect.createSelector(selectBuiltinCollections, selectMyPublishedCollections, selectMyUnpublishedCollections, selectMyEditedCollections, selectPendingCollections, (bLists, myRLists, uLists, eLists, pLists) => {
const collections = [bLists, uLists, eLists, myRLists, pLists];
const itemsInCollections = [];
collections.map(list => {
Object.entries(list).forEach(([key, value]) => {
// $FlowFixMe
value.items.map(item => {
itemsInCollections.push(item);
});
});
});
return itemsInCollections.includes(url);
});
const makeSelectCollectionForIdHasClaimUrl = (id, url) => reselect.createSelector(makeSelectCollectionForId(id), collection => collection && collection.items.includes(url)); const makeSelectCollectionForIdHasClaimUrl = (id, url) => reselect.createSelector(makeSelectCollectionForId(id), collection => collection && collection.items.includes(url));
const makeSelectUrlsForCollectionId = id => reselect.createSelector(makeSelectCollectionForId(id), collection => collection && collection.items); const makeSelectUrlsForCollectionId = id => reselect.createSelector(makeSelectCollectionForId(id), collection => collection && collection.items);
@ -3682,23 +3730,51 @@ const makeSelectClaimIdsForCollectionId = id => reselect.createSelector(makeSele
return ids; return ids;
}); });
const makeSelectIndexForUrlInCollection = (url, id) => reselect.createSelector(makeSelectUrlsForCollectionId(id), makeSelectClaimForUri(url), (urls, claim) => { const makeSelectIndexForUrlInCollection = (url, id) => reselect.createSelector(state => state.content.shuffleList, makeSelectUrlsForCollectionId(id), makeSelectClaimForUri(url), (shuffleState, urls, claim) => {
const index = urls && urls.findIndex(u => u === url); const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
const listUrls = shuffleUrls || urls;
const index = listUrls && listUrls.findIndex(u => u === url);
if (index > -1) { if (index > -1) {
return index; return index;
} else if (claim) { } else if (claim) {
const index = urls && urls.findIndex(u => u === claim.permanent_url); const index = listUrls && listUrls.findIndex(u => u === claim.permanent_url);
if (index > -1) return index; if (index > -1) return index;
return claim; return claim;
} }
return null; return null;
}); });
const makeSelectNextUrlForCollectionAndUrl = (id, url) => reselect.createSelector(makeSelectIndexForUrlInCollection(url, id), selectClaimsByUri, makeSelectUrlsForCollectionId(id), (index, claims, urls) => { const makeSelectPreviousUrlForCollectionAndUrl = (id, url) => reselect.createSelector(state => state.content.shuffleList, state => state.content.loopList, makeSelectIndexForUrlInCollection(url, id), makeSelectUrlsForCollectionId(id), (shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) { if (index > -1) {
const listUrls = shuffleUrls || urls;
let nextUrl;
if (index === 0 && loopList) {
nextUrl = listUrls[listUrls.length - 1];
} else {
nextUrl = listUrls[index - 1];
}
return nextUrl || null;
} else {
return null;
}
});
const makeSelectNextUrlForCollectionAndUrl = (id, url) => reselect.createSelector(state => state.content.shuffleList, state => state.content.loopList, makeSelectIndexForUrlInCollection(url, id), makeSelectUrlsForCollectionId(id), (shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) {
const listUrls = shuffleUrls || urls;
// We'll get the next playble url // We'll get the next playble url
const remainingUrls = urls.slice(index + 1); let remainingUrls = listUrls.slice(index + 1);
const nextUrl = remainingUrls.find(u => claims[u].value.stream_type && (claims[u].value.stream_type === 'video' || claims[u].value.stream_type === 'audio')); if (!remainingUrls.length && loopList) {
remainingUrls = listUrls.slice(0);
}
const nextUrl = remainingUrls && remainingUrls[0];
return nextUrl || null; return nextUrl || null;
} else { } else {
return null; return null;
@ -3714,7 +3790,13 @@ const makeSelectCountForCollectionId = id => reselect.createSelector(makeSelectC
if (collection.itemCount !== undefined) { if (collection.itemCount !== undefined) {
return collection.itemCount; return collection.itemCount;
} }
return collection.items.length; let itemCount = 0;
collection.items.map(item => {
if (item) {
itemCount += 1;
}
});
return itemCount;
} }
return null; return null;
}); });
@ -4420,11 +4502,15 @@ function doCollectionPublish(options, localId) {
}; };
} }
function doCollectionPublishUpdate(options) { function doCollectionPublishUpdate(options, isBackgroundUpdate) {
return dispatch => { return (dispatch, getState) => {
// TODO: implement one click update // TODO: implement one click update
const updateParams = { const updateParams = isBackgroundUpdate ? {
blocking: true,
claim_id: options.claim_id,
clear_claims: true
} : {
bid: creditsToString(options.bid), bid: creditsToString(options.bid),
title: options.title, title: options.title,
thumbnail_url: options.thumbnail_url, thumbnail_url: options.thumbnail_url,
@ -4434,16 +4520,25 @@ function doCollectionPublishUpdate(options) {
locations: [], locations: [],
blocking: true, blocking: true,
claim_id: options.claim_id, claim_id: options.claim_id,
clear_claims: true clear_claims: true,
replace: true
}; };
if (isBackgroundUpdate && updateParams.claim_id) {
const state = getState();
updateParams['claims'] = makeSelectClaimIdsForCollectionId(updateParams.claim_id)(state);
} else if (options.claims) {
updateParams['claims'] = options.claims;
}
if (options.tags) { if (options.tags) {
updateParams['tags'] = options.tags.map(tag => tag.name); updateParams['tags'] = options.tags.map(tag => tag.name);
} }
if (options.claims) { if (options.channel_id) {
updateParams['claims'] = options.claims; updateParams['channel_id'] = options.channel_id;
} }
return new Promise(resolve => { return new Promise(resolve => {
dispatch({ dispatch({
type: COLLECTION_PUBLISH_UPDATE_STARTED type: COLLECTION_PUBLISH_UPDATE_STARTED
@ -4613,7 +4708,7 @@ const getTimestamp = () => {
return Math.floor(Date.now() / 1000); return Math.floor(Date.now() / 1000);
}; };
const FETCH_BATCH_SIZE = 10; const FETCH_BATCH_SIZE = 50;
const doLocalCollectionCreate = (name, collectionItems, type, sourceId) => dispatch => { const doLocalCollectionCreate = (name, collectionItems, type, sourceId) => dispatch => {
return dispatch({ return dispatch({
@ -4720,7 +4815,8 @@ const doFetchItemsInCollections = (resolveItemsOptions, resolveStartedCallback)
batches[i] = lbryProxy.claim_search({ batches[i] = lbryProxy.claim_search({
claim_ids: claim.value.claims, claim_ids: claim.value.claims,
page: i + 1, page: i + 1,
page_size: batchSize page_size: batchSize,
no_totals: true
}); });
} }
const itemsInBatches = yield Promise.all(batches); const itemsInBatches = yield Promise.all(batches);
@ -5537,7 +5633,7 @@ const doUpdatePublishForm = publishFormValue => dispatch => dispatch({
data: _extends$7({}, publishFormValue) data: _extends$7({}, publishFormValue)
}); });
const doUploadThumbnail = (filePath, thumbnailBlob, fsAdapter, fs, path) => dispatch => { const doUploadThumbnail = (filePath, thumbnailBlob, fsAdapter, fs, path, cb) => dispatch => {
const downMessage = __('Thumbnail upload service may be down, try again later.'); const downMessage = __('Thumbnail upload service may be down, try again later.');
let thumbnail, fileExt, fileName, fileType; let thumbnail, fileExt, fileName, fileType;
@ -5571,13 +5667,17 @@ const doUploadThumbnail = (filePath, thumbnailBlob, fsAdapter, fs, path) => disp
method: 'POST', method: 'POST',
body: data body: data
}).then(res => res.text()).then(text => text.length ? JSON.parse(text) : {}).then(json => { }).then(res => res.text()).then(text => text.length ? JSON.parse(text) : {}).then(json => {
return json.success ? dispatch({ if (!json.success) return uploadError(json.message || downMessage);
if (cb) {
cb(json.data.serveUrl);
}
return dispatch({
type: UPDATE_PUBLISH_FORM, type: UPDATE_PUBLISH_FORM,
data: { data: {
uploadThumbnailStatus: COMPLETE, uploadThumbnailStatus: COMPLETE,
thumbnail: json.data.serveUrl thumbnail: json.data.serveUrl
} }
}) : uploadError(json.message || downMessage); });
}).catch(err => { }).catch(err => {
let message = err.message; let message = err.message;
@ -7672,8 +7772,15 @@ const collectionsReducer = handleActions({
[COLLECTION_PENDING]: (state, action) => { [COLLECTION_PENDING]: (state, action) => {
const { localId, claimId } = action.data; const { localId, claimId } = action.data;
const { edited: editList, unpublished: unpublishedList, pending: pendingList } = state; const {
resolved: resolvedList,
edited: editList,
unpublished: unpublishedList,
pending: pendingList
} = state;
const newEditList = Object.assign({}, editList); const newEditList = Object.assign({}, editList);
const newResolvedList = Object.assign({}, resolvedList);
const newUnpublishedList = Object.assign({}, unpublishedList); const newUnpublishedList = Object.assign({}, unpublishedList);
const newPendingList = Object.assign({}, pendingList); const newPendingList = Object.assign({}, pendingList);
@ -7683,7 +7790,7 @@ const collectionsReducer = handleActions({
delete newUnpublishedList[localId]; delete newUnpublishedList[localId];
} else { } else {
// edit update // edit update
newPendingList[claimId] = Object.assign({}, newEditList[claimId]); newPendingList[claimId] = Object.assign({}, newEditList[claimId] || newResolvedList[claimId]);
delete newEditList[claimId]; delete newEditList[claimId];
} }
@ -7735,8 +7842,14 @@ const collectionsReducer = handleActions({
})); }));
}, },
[USER_STATE_POPULATE]: (state, action) => { [USER_STATE_POPULATE]: (state, action) => {
const { builtinCollections, savedCollections, unpublishedCollections } = action.data; const {
builtinCollections,
savedCollections,
unpublishedCollections,
editedCollections
} = action.data;
return _extends$e({}, state, { return _extends$e({}, state, {
edited: editedCollections || state.edited,
unpublished: unpublishedCollections || state.unpublished, unpublished: unpublishedCollections || state.unpublished,
builtin: builtinCollections || state.builtin, builtin: builtinCollections || state.builtin,
saved: savedCollections || state.saved saved: savedCollections || state.saved
@ -7936,6 +8049,7 @@ exports.formatFullPrice = formatFullPrice;
exports.isClaimNsfw = isClaimNsfw; exports.isClaimNsfw = isClaimNsfw;
exports.isNameValid = isNameValid; exports.isNameValid = isNameValid;
exports.isURIClaimable = isURIClaimable; exports.isURIClaimable = isURIClaimable;
exports.isURIEqual = isURIEqual;
exports.isURIValid = isURIValid; exports.isURIValid = isURIValid;
exports.makeSelectAbandoningClaimById = makeSelectAbandoningClaimById; exports.makeSelectAbandoningClaimById = makeSelectAbandoningClaimById;
exports.makeSelectAmountForUri = makeSelectAmountForUri; exports.makeSelectAmountForUri = makeSelectAmountForUri;
@ -7952,6 +8066,7 @@ exports.makeSelectClaimIsMine = makeSelectClaimIsMine;
exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw; exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw;
exports.makeSelectClaimIsPending = makeSelectClaimIsPending; exports.makeSelectClaimIsPending = makeSelectClaimIsPending;
exports.makeSelectClaimIsStreamPlaceholder = makeSelectClaimIsStreamPlaceholder; exports.makeSelectClaimIsStreamPlaceholder = makeSelectClaimIsStreamPlaceholder;
exports.makeSelectClaimUrlInCollection = makeSelectClaimUrlInCollection;
exports.makeSelectClaimWasPurchased = makeSelectClaimWasPurchased; exports.makeSelectClaimWasPurchased = makeSelectClaimWasPurchased;
exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage; exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage;
exports.makeSelectCollectionForId = makeSelectCollectionForId; exports.makeSelectCollectionForId = makeSelectCollectionForId;
@ -7992,6 +8107,7 @@ exports.makeSelectPendingAmountByUri = makeSelectPendingAmountByUri;
exports.makeSelectPendingClaimForUri = makeSelectPendingClaimForUri; exports.makeSelectPendingClaimForUri = makeSelectPendingClaimForUri;
exports.makeSelectPendingCollectionForId = makeSelectPendingCollectionForId; exports.makeSelectPendingCollectionForId = makeSelectPendingCollectionForId;
exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri; exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri;
exports.makeSelectPreviousUrlForCollectionAndUrl = makeSelectPreviousUrlForCollectionAndUrl;
exports.makeSelectPublishFormValue = makeSelectPublishFormValue; exports.makeSelectPublishFormValue = makeSelectPublishFormValue;
exports.makeSelectPublishedCollectionForId = makeSelectPublishedCollectionForId; exports.makeSelectPublishedCollectionForId = makeSelectPublishedCollectionForId;
exports.makeSelectReflectingClaimForUri = makeSelectReflectingClaimForUri; exports.makeSelectReflectingClaimForUri = makeSelectReflectingClaimForUri;
@ -8151,5 +8267,6 @@ exports.selectWalletState = selectWalletState;
exports.selectWalletUnlockPending = selectWalletUnlockPending; exports.selectWalletUnlockPending = selectWalletUnlockPending;
exports.selectWalletUnlockResult = selectWalletUnlockResult; exports.selectWalletUnlockResult = selectWalletUnlockResult;
exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded; exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded;
exports.splitBySeparator = splitBySeparator;
exports.toQueryString = toQueryString; exports.toQueryString = toQueryString;
exports.walletReducer = walletReducer; exports.walletReducer = walletReducer;

5
dist/flow-typed/npm/from-entries.js vendored Normal file
View file

@ -0,0 +1,5 @@
// @flow
declare module '@ungap/from-entries' {
declare module.exports: any;
}

5
flow-typed/npm/from-entries.js vendored Normal file
View file

@ -0,0 +1,5 @@
// @flow
declare module '@ungap/from-entries' {
declare module.exports: any;
}

View file

@ -29,6 +29,7 @@
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"@ungap/from-entries": "^0.2.1",
"proxy-polyfill": "0.1.6", "proxy-polyfill": "0.1.6",
"reselect": "^3.0.0", "reselect": "^3.0.0",
"uuid": "^8.3.1" "uuid": "^8.3.1"

View file

@ -23,7 +23,7 @@ export const INSTANT_PURCHASE_MAX = 'instant_purchase_max';
export const THEME = 'theme'; export const THEME = 'theme';
export const THEMES = 'themes'; export const THEMES = 'themes';
export const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled'; export const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled';
export const AUTOPLAY = 'autoplay'; export const AUTOPLAY_MEDIA = 'autoplay';
export const AUTOPLAY_NEXT = 'autoplay_next'; export const AUTOPLAY_NEXT = 'autoplay_next';
export const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled'; export const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled';
export const AUTO_DOWNLOAD = 'auto_download'; export const AUTO_DOWNLOAD = 'auto_download';
@ -39,6 +39,8 @@ export const ENABLE_PUBLISH_PREVIEW = 'enable-publish-preview';
export const TILE_LAYOUT = 'tile_layout'; export const TILE_LAYOUT = 'tile_layout';
export const VIDEO_THEATER_MODE = 'video_theater_mode'; export const VIDEO_THEATER_MODE = 'video_theater_mode';
export const VIDEO_PLAYBACK_RATE = 'video_playback_rate'; export const VIDEO_PLAYBACK_RATE = 'video_playback_rate';
export const CUSTOM_COMMENTS_SERVER_ENABLED = 'custom_comments_server_enabled';
export const CUSTOM_COMMENTS_SERVER_URL = 'custom_comments_server_url';
// mobile settings // mobile settings
export const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled'; export const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled';

View file

@ -21,10 +21,12 @@ export const CLIENT_SYNC_KEYS = [
SETTINGS.INSTANT_PURCHASE_ENABLED, SETTINGS.INSTANT_PURCHASE_ENABLED,
SETTINGS.INSTANT_PURCHASE_MAX, SETTINGS.INSTANT_PURCHASE_MAX,
SETTINGS.THEME, SETTINGS.THEME,
SETTINGS.AUTOPLAY, SETTINGS.AUTOPLAY_MEDIA,
SETTINGS.AUTOPLAY_NEXT,
SETTINGS.HIDE_BALANCE, SETTINGS.HIDE_BALANCE,
SETTINGS.HIDE_SPLASH_ANIMATION, SETTINGS.HIDE_SPLASH_ANIMATION,
SETTINGS.FLOATING_PLAYER, SETTINGS.FLOATING_PLAYER,
SETTINGS.DARK_MODE_TIMES, SETTINGS.DARK_MODE_TIMES,
SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, SETTINGS.AUTOMATIC_DARK_MODE_ENABLED,
SETTINGS.LANGUAGE,
]; ];

View file

@ -52,6 +52,8 @@ export {
isURIClaimable, isURIClaimable,
isNameValid, isNameValid,
convertToShareLink, convertToShareLink,
splitBySeparator,
isURIEqual,
} from 'lbryURI'; } from 'lbryURI';
// middlware // middlware
@ -174,12 +176,14 @@ export {
makeSelectMyPublishedCollectionForId, makeSelectMyPublishedCollectionForId,
makeSelectUnpublishedCollectionForId, makeSelectUnpublishedCollectionForId,
makeSelectCollectionForId, makeSelectCollectionForId,
makeSelectClaimUrlInCollection,
makeSelectUrlsForCollectionId, makeSelectUrlsForCollectionId,
makeSelectClaimIdsForCollectionId, makeSelectClaimIdsForCollectionId,
makeSelectNameForCollectionId, makeSelectNameForCollectionId,
makeSelectCountForCollectionId, makeSelectCountForCollectionId,
makeSelectIsResolvingCollectionForId, makeSelectIsResolvingCollectionForId,
makeSelectIndexForUrlInCollection, makeSelectIndexForUrlInCollection,
makeSelectPreviousUrlForCollectionAndUrl,
makeSelectNextUrlForCollectionAndUrl, makeSelectNextUrlForCollectionAndUrl,
makeSelectCollectionForIdHasClaimUrl, makeSelectCollectionForIdHasClaimUrl,
} from 'redux/selectors/collections'; } from 'redux/selectors/collections';

View file

@ -4,7 +4,7 @@ const channelNameMinLength = 1;
const claimIdMaxLength = 40; const claimIdMaxLength = 40;
// see https://spec.lbry.com/#urls // see https://spec.lbry.com/#urls
export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%\{\}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u; export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
const regexPartProtocol = '^((?:lbry://)?)'; const regexPartProtocol = '^((?:lbry://)?)';
const regexPartStreamOrChannelName = '([^:$#/]*)'; const regexPartStreamOrChannelName = '([^:$#/]*)';
@ -12,6 +12,11 @@ const regexPartModifierSeparator = '([:$#]?)([^/]*)';
const queryStringBreaker = '^([\\S]+)([?][\\S]*)'; const queryStringBreaker = '^([\\S]+)([?][\\S]*)';
const separateQuerystring = new RegExp(queryStringBreaker); const separateQuerystring = new RegExp(queryStringBreaker);
const MOD_SEQUENCE_SEPARATOR = '*';
const MOD_CLAIM_ID_SEPARATOR_OLD = '#';
const MOD_CLAIM_ID_SEPARATOR = ':';
const MOD_BID_POSITION_SEPARATOR = '$';
/** /**
* Parses a LBRY name into its component parts. Throws errors with user-friendly * Parses a LBRY name into its component parts. Throws errors with user-friendly
* messages for invalid names. * messages for invalid names.
@ -144,11 +149,11 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator }));
} }
if (modSeperator === '#') { if (modSeperator === MOD_CLAIM_ID_SEPARATOR || MOD_CLAIM_ID_SEPARATOR_OLD) {
claimId = modValue; claimId = modValue;
} else if (modSeperator === ':') { } else if (modSeperator === MOD_SEQUENCE_SEPARATOR) {
claimSequence = modValue; claimSequence = modValue;
} else if (modSeperator === '$') { } else if (modSeperator === MOD_BID_POSITION_SEPARATOR) {
bidPosition = modValue; bidPosition = modValue;
} }
} }
@ -320,3 +325,22 @@ export function convertToShareLink(URL: string) {
'https://open.lbry.com/' 'https://open.lbry.com/'
); );
} }
export function splitBySeparator(uri: string) {
const protocolLength = 7;
return uri.startsWith('lbry://') ? uri.slice(protocolLength).split(/[#:*]/) : uri.split(/#:\*\$/);
}
export function isURIEqual(uriA: string, uriB: string) {
const parseA = parseURI(normalizeURI(uriA));
const parseB = parseURI(normalizeURI(uriB));
if (parseA.isChannel) {
if (parseB.isChannel && parseA.channelClaimId === parseB.channelClaimId) {
return true;
}
} else if (parseA.streamClaimId === parseB.streamClaimId) {
return true;
} else {
return false;
}
}

View file

@ -19,7 +19,10 @@ import { creditsToString } from 'util/format-credits';
import { batchActions } from 'util/batch-actions'; import { batchActions } from 'util/batch-actions';
import { createNormalizedClaimSearchKey } from 'util/claim'; import { createNormalizedClaimSearchKey } from 'util/claim';
import { PAGE_SIZE } from 'constants/claim'; import { PAGE_SIZE } from 'constants/claim';
import { selectPendingCollections } from 'redux/selectors/collections'; import {
selectPendingCollections,
makeSelectClaimIdsForCollectionId,
} from 'redux/selectors/collections';
import { import {
doFetchItemsInCollection, doFetchItemsInCollection,
doFetchItemsInCollections, doFetchItemsInCollections,
@ -828,18 +831,22 @@ export function doCollectionPublish(
}; };
} }
export function doCollectionPublishUpdate(options: { export function doCollectionPublishUpdate(
bid?: string, options: {
blocking?: true, bid?: string,
title?: string, blocking?: true,
thumbnail_url?: string, title?: string,
description?: string, thumbnail_url?: string,
claim_id: string, description?: string,
tags?: Array<Tag>, claim_id: string,
languages?: Array<string>, tags?: Array<Tag>,
claims?: Array<string>, languages?: Array<string>,
}) { claims?: Array<string>,
return (dispatch: Dispatch): Promise<any> => { channel_id?: string,
},
isBackgroundUpdate?: boolean
) {
return (dispatch: Dispatch, getState: GetState): Promise<any> => {
// TODO: implement one click update // TODO: implement one click update
const updateParams: { const updateParams: {
@ -847,32 +854,49 @@ export function doCollectionPublishUpdate(options: {
blocking?: true, blocking?: true,
title?: string, title?: string,
thumbnail_url?: string, thumbnail_url?: string,
channel_id?: string,
description?: string, description?: string,
claim_id: string, claim_id: string,
tags?: Array<string>, tags?: Array<string>,
languages?: Array<string>, languages?: Array<string>,
claims?: Array<string>, claims?: Array<string>,
clear_claims: boolean, clear_claims: boolean,
} = { replace?: boolean,
bid: creditsToString(options.bid), } = isBackgroundUpdate
title: options.title, ? {
thumbnail_url: options.thumbnail_url, blocking: true,
description: options.description, claim_id: options.claim_id,
tags: [], clear_claims: true,
languages: options.languages || [], }
locations: [], : {
blocking: true, bid: creditsToString(options.bid),
claim_id: options.claim_id, title: options.title,
clear_claims: true, thumbnail_url: options.thumbnail_url,
}; description: options.description,
tags: [],
languages: options.languages || [],
locations: [],
blocking: true,
claim_id: options.claim_id,
clear_claims: true,
replace: true,
};
if (isBackgroundUpdate && updateParams.claim_id) {
const state = getState();
updateParams['claims'] = makeSelectClaimIdsForCollectionId(updateParams.claim_id)(state);
} else if (options.claims) {
updateParams['claims'] = options.claims;
}
if (options.tags) { if (options.tags) {
updateParams['tags'] = options.tags.map(tag => tag.name); updateParams['tags'] = options.tags.map(tag => tag.name);
} }
if (options.claims) { if (options.channel_id) {
updateParams['claims'] = options.claims; updateParams['channel_id'] = options.channel_id;
} }
return new Promise(resolve => { return new Promise(resolve => {
dispatch({ dispatch({
type: ACTIONS.COLLECTION_PUBLISH_UPDATE_STARTED, type: ACTIONS.COLLECTION_PUBLISH_UPDATE_STARTED,

View file

@ -18,7 +18,7 @@ const getTimestamp = () => {
return Math.floor(Date.now() / 1000); return Math.floor(Date.now() / 1000);
}; };
const FETCH_BATCH_SIZE = 10; const FETCH_BATCH_SIZE = 50;
export const doLocalCollectionCreate = ( export const doLocalCollectionCreate = (
name: string, name: string,
@ -93,7 +93,7 @@ export const doFetchItemsInCollections = (
pageSize?: number, pageSize?: number,
}, },
resolveStartedCallback?: () => void resolveStartedCallback?: () => void
) => async (dispatch: Dispatch, getState: GetState) => { ) => async(dispatch: Dispatch, getState: GetState) => {
/* /*
1) make sure all the collection claims are loaded into claims reducer, search/resolve if necessary. 1) make sure all the collection claims are loaded into claims reducer, search/resolve if necessary.
2) get the item claims for each 2) get the item claims for each
@ -165,6 +165,7 @@ export const doFetchItemsInCollections = (
claim_ids: claim.value.claims, claim_ids: claim.value.claims,
page: i + 1, page: i + 1,
page_size: batchSize, page_size: batchSize,
no_totals: true,
}); });
} }
const itemsInBatches = await Promise.all(batches); const itemsInBatches = await Promise.all(batches);
@ -318,7 +319,7 @@ export const doFetchItemsInCollection = (
return doFetchItemsInCollections(newOptions, cb); return doFetchItemsInCollections(newOptions, cb);
}; };
export const doCollectionEdit = (collectionId: string, params: CollectionEditParams) => async ( export const doCollectionEdit = (collectionId: string, params: CollectionEditParams) => async(
dispatch: Dispatch, dispatch: Dispatch,
getState: GetState getState: GetState
) => { ) => {

View file

@ -69,7 +69,8 @@ export const doUploadThumbnail = (
thumbnailBlob?: File, thumbnailBlob?: File,
fsAdapter?: any, fsAdapter?: any,
fs?: any, fs?: any,
path?: any path?: any,
cb?: (string) => void
) => (dispatch: Dispatch) => { ) => (dispatch: Dispatch) => {
const downMessage = __('Thumbnail upload service may be down, try again later.'); const downMessage = __('Thumbnail upload service may be down, try again later.');
let thumbnail, fileExt, fileName, fileType; let thumbnail, fileExt, fileName, fileType;
@ -112,15 +113,17 @@ export const doUploadThumbnail = (
.then(res => res.text()) .then(res => res.text())
.then(text => (text.length ? JSON.parse(text) : {})) .then(text => (text.length ? JSON.parse(text) : {}))
.then(json => { .then(json => {
return json.success if (!json.success) return uploadError(json.message || downMessage);
? dispatch({ if (cb) {
type: ACTIONS.UPDATE_PUBLISH_FORM, cb(json.data.serveUrl);
data: { }
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE, return dispatch({
thumbnail: json.data.serveUrl, type: ACTIONS.UPDATE_PUBLISH_FORM,
}, data: {
}) uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
: uploadError(json.message || downMessage); thumbnail: json.data.serveUrl,
},
});
}) })
.catch(err => { .catch(err => {
let message = err.message; let message = err.message;

View file

@ -14,6 +14,7 @@ type SharedData = {
app_welcome_version?: number, app_welcome_version?: number,
sharing_3P?: boolean, sharing_3P?: boolean,
unpublishedCollections: CollectionGroup, unpublishedCollections: CollectionGroup,
editedCollections: CollectionGroup,
builtinCollections: CollectionGroup, builtinCollections: CollectionGroup,
savedCollections: Array<string>, savedCollections: Array<string>,
}, },
@ -31,6 +32,7 @@ function extractUserState(rawObj: SharedData) {
app_welcome_version, app_welcome_version,
sharing_3P, sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections, savedCollections,
} = rawObj.value; } = rawObj.value;
@ -45,6 +47,7 @@ function extractUserState(rawObj: SharedData) {
...(app_welcome_version ? { app_welcome_version } : {}), ...(app_welcome_version ? { app_welcome_version } : {}),
...(sharing_3P ? { sharing_3P } : {}), ...(sharing_3P ? { sharing_3P } : {}),
...(unpublishedCollections ? { unpublishedCollections } : {}), ...(unpublishedCollections ? { unpublishedCollections } : {}),
...(editedCollections ? { editedCollections } : {}),
...(builtinCollections ? { builtinCollections } : {}), ...(builtinCollections ? { builtinCollections } : {}),
...(savedCollections ? { savedCollections } : {}), ...(savedCollections ? { savedCollections } : {}),
}; };
@ -65,6 +68,7 @@ export function doPopulateSharedUserState(sharedSettings: any) {
app_welcome_version, app_welcome_version,
sharing_3P, sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections, savedCollections,
} = extractUserState(sharedSettings); } = extractUserState(sharedSettings);
@ -80,6 +84,7 @@ export function doPopulateSharedUserState(sharedSettings: any) {
welcomeVersion: app_welcome_version, welcomeVersion: app_welcome_version,
allowAnalytics: sharing_3P, allowAnalytics: sharing_3P,
unpublishedCollections, unpublishedCollections,
editedCollections,
builtinCollections, builtinCollections,
savedCollections, savedCollections,
}, },

View file

@ -90,8 +90,15 @@ const collectionsReducer = handleActions(
[ACTIONS.COLLECTION_PENDING]: (state, action) => { [ACTIONS.COLLECTION_PENDING]: (state, action) => {
const { localId, claimId } = action.data; const { localId, claimId } = action.data;
const { edited: editList, unpublished: unpublishedList, pending: pendingList } = state; const {
resolved: resolvedList,
edited: editList,
unpublished: unpublishedList,
pending: pendingList,
} = state;
const newEditList = Object.assign({}, editList); const newEditList = Object.assign({}, editList);
const newResolvedList = Object.assign({}, resolvedList);
const newUnpublishedList = Object.assign({}, unpublishedList); const newUnpublishedList = Object.assign({}, unpublishedList);
const newPendingList = Object.assign({}, pendingList); const newPendingList = Object.assign({}, pendingList);
@ -101,7 +108,10 @@ const collectionsReducer = handleActions(
delete newUnpublishedList[localId]; delete newUnpublishedList[localId];
} else { } else {
// edit update // edit update
newPendingList[claimId] = Object.assign({}, newEditList[claimId]); newPendingList[claimId] = Object.assign(
{},
newEditList[claimId] || newResolvedList[claimId]
);
delete newEditList[claimId]; delete newEditList[claimId];
} }
@ -158,9 +168,15 @@ const collectionsReducer = handleActions(
}); });
}, },
[ACTIONS.USER_STATE_POPULATE]: (state, action) => { [ACTIONS.USER_STATE_POPULATE]: (state, action) => {
const { builtinCollections, savedCollections, unpublishedCollections } = action.data; const {
builtinCollections,
savedCollections,
unpublishedCollections,
editedCollections,
} = action.data;
return { return {
...state, ...state,
edited: editedCollections || state.edited,
unpublished: unpublishedCollections || state.unpublished, unpublished: unpublishedCollections || state.unpublished,
builtin: builtinCollections || state.builtin, builtin: builtinCollections || state.builtin,
saved: savedCollections || state.saved, saved: savedCollections || state.saved,

View file

@ -165,7 +165,7 @@ export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true)
return { return {
...repostedClaim, ...repostedClaim,
repost_url: uri, repost_url: normalizeURI(uri),
repost_channel_url: channelUrl, repost_channel_url: channelUrl,
repost_bid_amount: claim && claim.meta && claim.meta.effective_amount, repost_bid_amount: claim && claim.meta && claim.meta.effective_amount,
}; };
@ -299,8 +299,8 @@ export const makeSelectMyPurchasesForPage = (query: ?string, page: number = 1) =
const end = Number(page) * Number(CLAIM.PAGE_SIZE); const end = Number(page) * Number(CLAIM.PAGE_SIZE);
return matchingFileInfos && matchingFileInfos.length return matchingFileInfos && matchingFileInfos.length
? matchingFileInfos ? matchingFileInfos
.slice(start, end) .slice(start, end)
.map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url) .map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url)
: []; : [];
} }
); );
@ -393,8 +393,8 @@ export const makeSelectDateForUri = (uri: string) =>
(claim.value.release_time (claim.value.release_time
? claim.value.release_time * 1000 ? claim.value.release_time * 1000
: claim.meta && claim.meta.creation_timestamp : claim.meta && claim.meta.creation_timestamp
? claim.meta.creation_timestamp * 1000 ? claim.meta.creation_timestamp * 1000
: null); : null);
if (!timestamp) { if (!timestamp) {
return undefined; return undefined;
} }
@ -630,13 +630,13 @@ export const makeSelectPendingClaimForUri = (uri: string) =>
export const makeSelectTotalItemsForChannel = (uri: string) => export const makeSelectTotalItemsForChannel = (uri: string) =>
createSelector( createSelector(
selectChannelClaimCounts, selectChannelClaimCounts,
byUri => byUri && byUri[uri] byUri => byUri && byUri[normalizeURI(uri)]
); );
export const makeSelectTotalPagesForChannel = (uri: string, pageSize: number = 10) => export const makeSelectTotalPagesForChannel = (uri: string, pageSize: number = 10) =>
createSelector( createSelector(
selectChannelClaimCounts, selectChannelClaimCounts,
byUri => byUri && byUri[uri] && Math.ceil(byUri[uri] / pageSize) byUri => byUri && byUri[uri] && Math.ceil(byUri[normalizeURI(uri)] / pageSize)
); );
export const makeSelectNsfwCountFromUris = (uris: Array<string>) => export const makeSelectNsfwCountFromUris = (uris: Array<string>) =>

View file

@ -1,4 +1,5 @@
// @flow // @flow
import fromEntries from '@ungap/from-entries';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { import {
selectMyCollectionIds, selectMyCollectionIds,
@ -79,7 +80,7 @@ export const selectMyPublishedCollections = createSelector(
selectMyCollectionIds, selectMyCollectionIds,
(resolved, pending, edited, myIds) => { (resolved, pending, edited, myIds) => {
// all resolved in myIds, plus those in pending and edited // all resolved in myIds, plus those in pending and edited
const myPublishedCollections = Object.fromEntries( const myPublishedCollections = fromEntries(
Object.entries(pending).concat( Object.entries(pending).concat(
Object.entries(resolved).filter( Object.entries(resolved).filter(
([key, val]) => ([key, val]) =>
@ -100,7 +101,7 @@ export const selectMyPublishedCollections = createSelector(
export const selectMyPublishedMixedCollections = createSelector( export const selectMyPublishedMixedCollections = createSelector(
selectMyPublishedCollections, selectMyPublishedCollections,
published => { published => {
const myCollections = Object.fromEntries( const myCollections = fromEntries(
// $FlowFixMe // $FlowFixMe
Object.entries(published).filter(([key, collection]) => { Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe // $FlowFixMe
@ -114,7 +115,7 @@ export const selectMyPublishedMixedCollections = createSelector(
export const selectMyPublishedPlaylistCollections = createSelector( export const selectMyPublishedPlaylistCollections = createSelector(
selectMyPublishedCollections, selectMyPublishedCollections,
published => { published => {
const myCollections = Object.fromEntries( const myCollections = fromEntries(
// $FlowFixMe // $FlowFixMe
Object.entries(published).filter(([key, collection]) => { Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe // $FlowFixMe
@ -135,7 +136,7 @@ export const makeSelectMyPublishedCollectionForId = (id: string) =>
// selectResolvedCollections, // selectResolvedCollections,
// selectSavedCollectionIds, // selectSavedCollectionIds,
// (resolved, myIds) => { // (resolved, myIds) => {
// const mySavedCollections = Object.fromEntries( // const mySavedCollections = fromEntries(
// Object.entries(resolved).filter(([key, val]) => myIds.includes(key)) // Object.entries(resolved).filter(([key, val]) => myIds.includes(key))
// ); // );
// return mySavedCollections; // return mySavedCollections;
@ -163,6 +164,28 @@ export const makeSelectCollectionForId = (id: string) =>
} }
); );
export const makeSelectClaimUrlInCollection = (url: string) =>
createSelector(
selectBuiltinCollections,
selectMyPublishedCollections,
selectMyUnpublishedCollections,
selectMyEditedCollections,
selectPendingCollections,
(bLists, myRLists, uLists, eLists, pLists) => {
const collections = [bLists, uLists, eLists, myRLists, pLists];
const itemsInCollections = [];
collections.map(list => {
Object.entries(list).forEach(([key, value]) => {
// $FlowFixMe
value.items.map(item => {
itemsInCollections.push(item);
});
});
});
return itemsInCollections.includes(url);
}
);
export const makeSelectCollectionForIdHasClaimUrl = (id: string, url: string) => export const makeSelectCollectionForIdHasClaimUrl = (id: string, url: string) =>
createSelector( createSelector(
makeSelectCollectionForId(id), makeSelectCollectionForId(id),
@ -190,14 +213,18 @@ export const makeSelectClaimIdsForCollectionId = (id: string) =>
export const makeSelectIndexForUrlInCollection = (url: string, id: string) => export const makeSelectIndexForUrlInCollection = (url: string, id: string) =>
createSelector( createSelector(
state => state.content.shuffleList,
makeSelectUrlsForCollectionId(id), makeSelectUrlsForCollectionId(id),
makeSelectClaimForUri(url), makeSelectClaimForUri(url),
(urls, claim) => { (shuffleState, urls, claim) => {
const index = urls && urls.findIndex(u => u === url); const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
const listUrls = shuffleUrls || urls;
const index = listUrls && listUrls.findIndex(u => u === url);
if (index > -1) { if (index > -1) {
return index; return index;
} else if (claim) { } else if (claim) {
const index = urls && urls.findIndex(u => u === claim.permanent_url); const index = listUrls && listUrls.findIndex(u => u === claim.permanent_url);
if (index > -1) return index; if (index > -1) return index;
return claim; return claim;
} }
@ -205,20 +232,49 @@ export const makeSelectIndexForUrlInCollection = (url: string, id: string) =>
} }
); );
export const makeSelectPreviousUrlForCollectionAndUrl = (id: string, url: string) =>
createSelector(
state => state.content.shuffleList,
state => state.content.loopList,
makeSelectIndexForUrlInCollection(url, id),
makeSelectUrlsForCollectionId(id),
(shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) {
const listUrls = shuffleUrls || urls;
let nextUrl;
if (index === 0 && loopList) {
nextUrl = listUrls[listUrls.length - 1];
} else {
nextUrl = listUrls[index - 1];
}
return nextUrl || null;
} else {
return null;
}
}
);
export const makeSelectNextUrlForCollectionAndUrl = (id: string, url: string) => export const makeSelectNextUrlForCollectionAndUrl = (id: string, url: string) =>
createSelector( createSelector(
state => state.content.shuffleList,
state => state.content.loopList,
makeSelectIndexForUrlInCollection(url, id), makeSelectIndexForUrlInCollection(url, id),
selectClaimsByUri,
makeSelectUrlsForCollectionId(id), makeSelectUrlsForCollectionId(id),
(index, claims, urls) => { (shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) { if (index > -1) {
const listUrls = shuffleUrls || urls;
// We'll get the next playble url // We'll get the next playble url
const remainingUrls = urls.slice(index + 1); let remainingUrls = listUrls.slice(index + 1);
const nextUrl = remainingUrls.find( if (!remainingUrls.length && loopList) {
u => remainingUrls = listUrls.slice(0);
claims[u].value.stream_type && }
(claims[u].value.stream_type === 'video' || claims[u].value.stream_type === 'audio') const nextUrl = remainingUrls && remainingUrls[0];
);
return nextUrl || null; return nextUrl || null;
} else { } else {
return null; return null;
@ -242,7 +298,13 @@ export const makeSelectCountForCollectionId = (id: string) =>
if (collection.itemCount !== undefined) { if (collection.itemCount !== undefined) {
return collection.itemCount; return collection.itemCount;
} }
return collection.items.length; let itemCount = 0;
collection.items.map(item => {
if (item) {
itemCount += 1;
}
});
return itemCount;
} }
return null; return null;
} }

View file

@ -1411,6 +1411,11 @@
dependencies: dependencies:
"@types/yargs-parser" "*" "@types/yargs-parser" "*"
"@ungap/from-entries@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@ungap/from-entries/-/from-entries-0.2.1.tgz#7e86196b8b2e99d73106a8f25c2a068326346354"
integrity sha512-CAqefTFAfnUPwYqsWHXpOxHaq1Zo5UQ3m9Zm2p09LggGe57rqHoBn3c++xcoomzXKynAUuiBMDUCQvKMnXjUpA==
abab@^1.0.4: abab@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"