// @flow import fromEntries from '@ungap/from-entries'; import { createSelector } from 'reselect'; import { selectMyCollectionIds, makeSelectClaimForUri } from 'redux/selectors/claims'; import { parseURI } from 'util/lbryURI'; import { isClaimPlayable } from 'util/claim'; const selectState = (state: { collections: CollectionState }) => state.collections; export const selectSavedCollectionIds = createSelector(selectState, (collectionState) => collectionState.saved); export const selectBuiltinCollections = createSelector(selectState, (state) => state.builtin); export const selectResolvedCollections = createSelector(selectState, (state) => state.resolved); export const selectMyUnpublishedCollections = createSelector(selectState, (state) => state.unpublished); export const selectMyEditedCollections = createSelector(selectState, (state) => state.edited); export const selectPendingCollections = createSelector(selectState, (state) => state.pending); export const selectLastUsedCollection = createSelector(selectState, (state) => state.lastUsedCollection); export const makeSelectEditedCollectionForId = (id: string) => createSelector(selectMyEditedCollections, (eLists) => eLists[id]); export const makeSelectPendingCollectionForId = (id: string) => createSelector(selectPendingCollections, (pending) => pending[id]); export const makeSelectPublishedCollectionForId = (id: string) => createSelector(selectResolvedCollections, (rLists) => rLists[id]); export const makeSelectUnpublishedCollectionForId = (id: string) => createSelector(selectMyUnpublishedCollections, (rLists) => rLists[id]); export const makeSelectCollectionIsMine = (id: string) => createSelector( selectMyCollectionIds, selectMyUnpublishedCollections, selectBuiltinCollections, (publicIds, privateIds, builtinIds) => { return Boolean(publicIds.includes(id) || privateIds[id] || builtinIds[id]); } ); export const selectMyPublishedCollections = createSelector( selectResolvedCollections, selectPendingCollections, selectMyEditedCollections, selectMyCollectionIds, (resolved, pending, edited, myIds) => { // all resolved in myIds, plus those in pending and edited const myPublishedCollections = fromEntries( Object.entries(pending).concat( Object.entries(resolved).filter( ([key, val]) => myIds.includes(key) && // $FlowFixMe !pending[key] ) ) ); // now add in edited: Object.entries(edited).forEach(([id, item]) => { myPublishedCollections[id] = item; }); return myPublishedCollections; } ); export const selectMyPublishedMixedCollections = createSelector(selectMyPublishedCollections, (published) => { const myCollections = fromEntries( // $FlowFixMe Object.entries(published).filter(([key, collection]) => { // $FlowFixMe return collection.type === 'collection'; }) ); return myCollections; }); export const selectMyPublishedPlaylistCollections = createSelector(selectMyPublishedCollections, (published) => { const myCollections = fromEntries( // $FlowFixMe Object.entries(published).filter(([key, collection]) => { // $FlowFixMe return collection.type === 'playlist'; }) ); return myCollections; }); export const makeSelectMyPublishedCollectionForId = (id: string) => createSelector(selectMyPublishedCollections, (myPublishedCollections) => myPublishedCollections[id]); // export const selectSavedCollections = createSelector( // selectResolvedCollections, // selectSavedCollectionIds, // (resolved, myIds) => { // const mySavedCollections = fromEntries( // Object.entries(resolved).filter(([key, val]) => myIds.includes(key)) // ); // return mySavedCollections; // } // ); export const makeSelectIsResolvingCollectionForId = (id: string) => createSelector(selectState, (state) => { return state.isResolvingCollectionById[id]; }); export const makeSelectCollectionForId = (id: string) => createSelector( selectBuiltinCollections, selectResolvedCollections, selectMyUnpublishedCollections, selectMyEditedCollections, selectPendingCollections, (bLists, rLists, uLists, eLists, pLists) => { const collection = bLists[id] || uLists[id] || eLists[id] || pLists[id] || rLists[id]; return collection; } ); 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) => createSelector(makeSelectCollectionForId(id), (collection) => collection && collection.items.includes(url)); export const makeSelectUrlsForCollectionId = (id: string) => createSelector(makeSelectCollectionForId(id), (collection) => collection && collection.items); export const makeSelectClaimIdsForCollectionId = (id: string) => createSelector(makeSelectCollectionForId(id), (collection) => { const items = (collection && collection.items) || []; const ids = items.map((item) => { const { claimId } = parseURI(item); return claimId; }); return ids; }); export const makeSelectIndexForUrlInCollection = (url: string, id: string, ignoreShuffle?: boolean) => createSelector( (state) => state.content.shuffleList, makeSelectUrlsForCollectionId(id), makeSelectClaimForUri(url), (shuffleState, urls, claim) => { const shuffleUrls = !ignoreShuffle && shuffleState && shuffleState.collectionId === id && shuffleState.newUrls; const listUrls = shuffleUrls || urls; const index = listUrls && listUrls.findIndex((u) => u === url); if (index > -1) { return index; } else if (claim) { const index = listUrls && listUrls.findIndex((u) => u === claim.permanent_url); if (index > -1) return index; return claim; } return null; } ); 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) => 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 playable url let remainingUrls = listUrls.slice(index + 1); if (!remainingUrls.length && loopList) { remainingUrls = listUrls.slice(0); } const nextUrl = remainingUrls && remainingUrls[0]; return nextUrl || null; } else { return null; } } ); export const makeSelectPrevPlayableUrlFromCollectionAndUrl = (collectionId: string, url: string) => createSelector( (state) => state, (state) => { let prevUrl = url; let prevPlayableClaim; do { prevUrl = makeSelectPreviousUrlForCollectionAndUrl(collectionId, prevUrl)(state); prevPlayableClaim = makeSelectClaimForUri(prevUrl)(state); } while (prevUrl && !isClaimPlayable(prevPlayableClaim)); return prevUrl; } ); export const makeSelectNextPlayableUrlFromCollectionAndUrl = (collectionId: string, url: string) => createSelector( (state) => state, (state) => { let nextUrl = url; let nextPlayableClaim; do { nextUrl = makeSelectNextUrlForCollectionAndUrl(collectionId, nextUrl)(state); nextPlayableClaim = makeSelectClaimForUri(nextUrl)(state); } while (nextUrl && !isClaimPlayable(nextPlayableClaim)); return nextUrl; } ); export const makeSelectNameForCollectionId = (id: string) => createSelector(makeSelectCollectionForId(id), (collection) => { return (collection && collection.name) || ''; }); export const makeSelectCountForCollectionId = (id: string) => createSelector(makeSelectCollectionForId(id), (collection) => { if (collection) { if (collection.itemCount !== undefined) { return collection.itemCount; } let itemCount = 0; collection.items.map((item) => { if (item) { itemCount += 1; } }); return itemCount; } return null; });