lbry-desktop/ui/redux/selectors/collections.js

282 lines
9.6 KiB
JavaScript

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