2021-10-08 05:47:39 +02:00
|
|
|
// @flow
|
|
|
|
import fromEntries from '@ungap/from-entries';
|
|
|
|
import { createSelector } from 'reselect';
|
|
|
|
import { selectMyCollectionIds, makeSelectClaimForUri } from 'redux/selectors/claims';
|
|
|
|
import { parseURI } from 'util/lbryURI';
|
2022-05-17 00:05:14 +02:00
|
|
|
import { isClaimPlayable } from 'util/claim';
|
2021-10-08 05:47:39 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2022-02-23 00:00:09 +01:00
|
|
|
export const selectLastUsedCollection = createSelector(selectState, (state) => state.lastUsedCollection);
|
|
|
|
|
2021-10-08 05:47:39 +02:00
|
|
|
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;
|
|
|
|
});
|
|
|
|
|
2022-01-27 16:20:21 +01:00
|
|
|
export const makeSelectIndexForUrlInCollection = (url: string, id: string, ignoreShuffle?: boolean) =>
|
2021-10-08 05:47:39 +02:00
|
|
|
createSelector(
|
|
|
|
(state) => state.content.shuffleList,
|
|
|
|
makeSelectUrlsForCollectionId(id),
|
|
|
|
makeSelectClaimForUri(url),
|
|
|
|
(shuffleState, urls, claim) => {
|
2022-01-27 16:20:21 +01:00
|
|
|
const shuffleUrls = !ignoreShuffle && shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
|
2021-10-08 05:47:39 +02:00
|
|
|
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;
|
2022-05-17 00:05:14 +02:00
|
|
|
// We'll get the next playable url
|
2021-10-08 05:47:39 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2022-05-17 00:05:14 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2021-10-08 05:47:39 +02:00
|
|
|
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;
|
|
|
|
});
|