Livestream category improvements #7115

Merged
infinite-persistence merged 15 commits from ip/category.livestream into master 2021-09-24 16:26:22 +02:00
8 changed files with 12 additions and 202 deletions
Showing only changes of commit ebda47576d - Show all commits

View file

@ -1,12 +1,10 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ClaimList from './view'; import ClaimList from './view';
import { SETTINGS, selectClaimSearchByQuery, selectClaimsByUri } from 'lbry-redux'; import { SETTINGS } from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
const select = (state) => ({ const select = (state) => ({
searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state), searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state),
claimSearchByQuery: selectClaimSearchByQuery(state),
claimsByUri: selectClaimsByUri(state),
}); });
export default connect(select)(ClaimList); export default connect(select)(ClaimList);

View file

@ -9,7 +9,6 @@ import { FormField } from 'component/common/form';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import debounce from 'util/debounce'; import debounce from 'util/debounce';
import ClaimPreviewTile from 'component/claimPreviewTile'; import ClaimPreviewTile from 'component/claimPreviewTile';
import { prioritizeActiveLivestreams } from 'component/claimTilesDiscover/view';
const DEBOUNCE_SCROLL_HANDLER_MS = 150; const DEBOUNCE_SCROLL_HANDLER_MS = 150;
const SORT_NEW = 'new'; const SORT_NEW = 'new';
@ -41,9 +40,6 @@ type Props = {
hideMenu?: boolean, hideMenu?: boolean,
claimSearchByQuery: { [string]: Array<string> }, claimSearchByQuery: { [string]: Array<string> },
claimsByUri: { [string]: any }, claimsByUri: { [string]: any },
liveLivestreamsFirst?: boolean,
livestreamMap?: { [string]: any },
searchOptions?: any,
collectionId?: string, collectionId?: string,
showNoSourceClaims?: boolean, showNoSourceClaims?: boolean,
onClick?: (e: any, claim?: ?Claim, index?: number) => void, onClick?: (e: any, claim?: ?Claim, index?: number) => void,
@ -73,11 +69,6 @@ export default function ClaimList(props: Props) {
renderProperties, renderProperties,
searchInLanguage, searchInLanguage,
hideMenu, hideMenu,
claimSearchByQuery,
claimsByUri,
liveLivestreamsFirst,
livestreamMap,
searchOptions,
collectionId, collectionId,
showNoSourceClaims, showNoSourceClaims,
onClick, onClick,
@ -87,23 +78,11 @@ export default function ClaimList(props: Props) {
const timedOut = uris === null; const timedOut = uris === null;
const urisLength = (uris && uris.length) || 0; const urisLength = (uris && uris.length) || 0;
const liveUris = [];
if (liveLivestreamsFirst && livestreamMap) {
prioritizeActiveLivestreams(uris, liveUris, livestreamMap, claimsByUri, claimSearchByQuery, searchOptions);
}
const sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? uris : uris.slice().reverse())) || []; const sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? uris : uris.slice().reverse())) || [];
const noResultMsg = searchInLanguage const noResultMsg = searchInLanguage
? __('No results. Contents may be hidden by the Language filter.') ? __('No results. Contents may be hidden by the Language filter.')
: __('No results'); : __('No results');
const resolveLive = (index) => {
if (liveLivestreamsFirst && livestreamMap && index < liveUris.length) {
return true;
}
return undefined;
};
function handleSortChange() { function handleSortChange() {
setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW); setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW);
} }
@ -138,13 +117,12 @@ export default function ClaimList(props: Props) {
return tileLayout && !header ? ( return tileLayout && !header ? (
<section className="claim-grid"> <section className="claim-grid">
{urisLength > 0 && {urisLength > 0 &&
uris.map((uri, index) => ( uris.map((uri) => (
<ClaimPreviewTile <ClaimPreviewTile
key={uri} key={uri}
uri={uri} uri={uri}
showHiddenByUser={showHiddenByUser} showHiddenByUser={showHiddenByUser}
properties={renderProperties} properties={renderProperties}
live={resolveLive(index)}
collectionId={collectionId} collectionId={collectionId}
showNoSourceClaims={showNoSourceClaims} showNoSourceClaims={showNoSourceClaims}
/> />
@ -216,7 +194,6 @@ export default function ClaimList(props: Props) {
// https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79 // https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79
return claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch'; return claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch';
}} }}
live={resolveLive(index)}
onClick={(e, claim, index) => handleClaimClicked(e, claim, index)} onClick={(e, claim, index) => handleClaimClicked(e, claim, index)}
/> />
</React.Fragment> </React.Fragment>

View file

@ -14,7 +14,6 @@ import ClaimPreviewTile from 'component/claimPreviewTile';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import ClaimListHeader from 'component/claimListHeader'; import ClaimListHeader from 'component/claimListHeader';
import { useIsLargeScreen } from 'effects/use-screensize'; import { useIsLargeScreen } from 'effects/use-screensize';
import { getLivestreamOnlyOptions } from 'util/search';
type Props = { type Props = {
uris: Array<string>, uris: Array<string>,
@ -31,7 +30,6 @@ type Props = {
includeSupportAction?: boolean, includeSupportAction?: boolean,
infiniteScroll?: Boolean, infiniteScroll?: Boolean,
isChannel?: boolean, isChannel?: boolean,
liveLivestreamsFirst?: boolean,
personalView: boolean, personalView: boolean,
showHeader: boolean, showHeader: boolean,
showHiddenByUser?: boolean, showHiddenByUser?: boolean,
@ -64,7 +62,6 @@ type Props = {
channelIds?: Array<string>, channelIds?: Array<string>,
claimIds?: Array<string>, claimIds?: Array<string>,
subscribedChannels: Array<Subscription>, subscribedChannels: Array<Subscription>,
livestreamMap?: { [string]: any },
header?: Node, header?: Node,
headerLabel?: string | Node, headerLabel?: string | Node,
@ -148,8 +145,6 @@ function ClaimListDiscover(props: Props) {
releaseTime, releaseTime,
scrollAnchor, scrollAnchor,
showHiddenByUser = false, showHiddenByUser = false,
liveLivestreamsFirst,
livestreamMap,
hasSource, hasSource,
hasNoSource, hasNoSource,
isChannel = false, isChannel = false,
@ -400,11 +395,6 @@ function ClaimListDiscover(props: Props) {
// claimSearchResult.splice(2, 0, fixUri); // claimSearchResult.splice(2, 0, fixUri);
// } // }
const livestreamSearchKey = liveLivestreamsFirst
? createNormalizedClaimSearchKey(getLivestreamOnlyOptions(options))
: undefined;
const livestreamSearchResult = livestreamSearchKey && claimSearchByQuery[livestreamSearchKey];
const [finalUris, setFinalUris] = React.useState( const [finalUris, setFinalUris] = React.useState(
getFinalUrisInitialState(history.action === 'POP', claimSearchResult) getFinalUrisInitialState(history.action === 'POP', claimSearchResult)
); );
@ -571,10 +561,6 @@ function ClaimListDiscover(props: Props) {
if (shouldPerformSearch) { if (shouldPerformSearch) {
const searchOptions = JSON.parse(optionsStringForEffect); const searchOptions = JSON.parse(optionsStringForEffect);
doClaimSearch(searchOptions); doClaimSearch(searchOptions);
if (liveLivestreamsFirst && options.page === 1) {
doClaimSearch(getLivestreamOnlyOptions(searchOptions));
}
} }
}, [doClaimSearch, shouldPerformSearch, optionsStringForEffect, forceRefresh]); }, [doClaimSearch, shouldPerformSearch, optionsStringForEffect, forceRefresh]);
@ -586,12 +572,12 @@ function ClaimListDiscover(props: Props) {
} }
} else { } else {
// Wait until all queries are done before updating the uris to avoid layout shifts. // Wait until all queries are done before updating the uris to avoid layout shifts.
const pending = claimSearchResult === undefined || (liveLivestreamsFirst && livestreamSearchResult === undefined); const pending = claimSearchResult === undefined;
if (!pending && !urisEqual(claimSearchResult, finalUris)) { if (!pending && !urisEqual(claimSearchResult, finalUris)) {
setFinalUris(claimSearchResult); setFinalUris(claimSearchResult);
} }
} }
}, [uris, claimSearchResult, finalUris, setFinalUris, liveLivestreamsFirst, livestreamSearchResult]); }, [uris, claimSearchResult, finalUris, setFinalUris]);
React.useEffect(() => { React.useEffect(() => {
if (fetchViewCount) { if (fetchViewCount) {
@ -645,8 +631,6 @@ function ClaimListDiscover(props: Props) {
includeSupportAction={includeSupportAction} includeSupportAction={includeSupportAction}
injectedItem={injectedItem} injectedItem={injectedItem}
showHiddenByUser={showHiddenByUser} showHiddenByUser={showHiddenByUser}
liveLivestreamsFirst={liveLivestreamsFirst}
livestreamMap={livestreamMap}
searchOptions={options} searchOptions={options}
showNoSourceClaims={showNoSourceClaims} showNoSourceClaims={showNoSourceClaims}
empty={empty} empty={empty}
@ -679,8 +663,6 @@ function ClaimListDiscover(props: Props) {
includeSupportAction={includeSupportAction} includeSupportAction={includeSupportAction}
injectedItem={injectedItem} injectedItem={injectedItem}
showHiddenByUser={showHiddenByUser} showHiddenByUser={showHiddenByUser}
liveLivestreamsFirst={liveLivestreamsFirst}
livestreamMap={livestreamMap}
searchOptions={options} searchOptions={options}
showNoSourceClaims={hasNoSource || showNoSourceClaims} showNoSourceClaims={hasNoSource || showNoSourceClaims}
empty={empty} empty={empty}

View file

@ -6,90 +6,11 @@ import React from 'react';
import { createNormalizedClaimSearchKey, MATURE_TAGS, splitBySeparator } from 'lbry-redux'; import { createNormalizedClaimSearchKey, MATURE_TAGS, splitBySeparator } from 'lbry-redux';
import ClaimPreviewTile from 'component/claimPreviewTile'; import ClaimPreviewTile from 'component/claimPreviewTile';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { getLivestreamOnlyOptions } from 'util/search';
/**
* Updates 'uris' by adding and/or moving active livestreams to the front of
* list.
* 'liveUris' is also updated with any entries that were moved to the
* front, for convenience.
*
* @param uris [Ref]
* @param liveUris [Ref]
* @param livestreamMap
* @param claimsByUri
* @param claimSearchByQuery
* @param options
*/
export function prioritizeActiveLivestreams(
uris: Array<string>,
liveUris: Array<string>,
livestreamMap: { [string]: any },
claimsByUri: { [string]: any },
claimSearchByQuery: { [string]: Array<string> },
options: any
) {
if (!livestreamMap || !uris) return;
const claimIsLive = (claim, liveChannelIds) => {
// This function relies on:
// 1. Only 1 actual livestream per channel (i.e. all other livestream-claims
// for that channel actually point to the same source).
// 2. 'liveChannelIds' needs to be pruned after being accounted for,
// otherwise all livestream-claims will be "live" (we'll only take the
// latest one as "live" ).
return (
claim &&
claim.value_type === 'stream' &&
claim.value.source === undefined &&
claim.signing_channel &&
liveChannelIds.includes(claim.signing_channel.claim_id)
);
};
let liveChannelIds = Object.keys(livestreamMap);
// 1. Collect active livestreams from the primary search to put in front.
uris.forEach((uri) => {
const claim = claimsByUri[uri];
if (claimIsLive(claim, liveChannelIds)) {
liveUris.push(uri);
// This live channel has been accounted for, so remove it.
liveChannelIds.splice(liveChannelIds.indexOf(claim.signing_channel.claim_id), 1);
}
});
// 2. Now, repeat on the secondary search.
if (options) {
const livestreamsOnlySearchCacheQuery = createNormalizedClaimSearchKey(getLivestreamOnlyOptions(options));
const livestreamsOnlyUris = claimSearchByQuery[livestreamsOnlySearchCacheQuery];
if (livestreamsOnlyUris) {
livestreamsOnlyUris.forEach((uri) => {
const claim = claimsByUri[uri];
if (!uris.includes(uri) && claimIsLive(claim, liveChannelIds)) {
liveUris.push(uri);
// This live channel has been accounted for, so remove it.
liveChannelIds.splice(liveChannelIds.indexOf(claim.signing_channel.claim_id), 1);
}
});
}
}
// 3. Finalize uris by putting live livestreams in front.
const newUris = liveUris.concat(uris.filter((uri) => !liveUris.includes(uri)));
uris.splice(0, uris.length, ...newUris);
}
// ****************************************************************************
// ClaimTilesDiscover
// ****************************************************************************
type Props = { type Props = {
prefixUris?: Array<string>, prefixUris?: Array<string>,
pinUrls?: Array<string>, pinUrls?: Array<string>,
uris: Array<string>, uris: Array<string>,
liveLivestreamsFirst?: boolean,
livestreamMap?: { [string]: any },
showNoSourceClaims?: boolean, showNoSourceClaims?: boolean,
renderProperties?: (Claim) => ?Node, renderProperties?: (Claim) => ?Node,
fetchViewCount?: boolean, fetchViewCount?: boolean,
@ -148,8 +69,6 @@ function ClaimTilesDiscover(props: Props) {
renderProperties, renderProperties,
blockedUris, blockedUris,
mutedUris, mutedUris,
liveLivestreamsFirst,
livestreamMap,
pinUrls, pinUrls,
prefixUris, prefixUris,
showNoSourceClaims, showNoSourceClaims,
@ -163,7 +82,7 @@ function ClaimTilesDiscover(props: Props) {
const mutedAndBlockedChannelIds = Array.from( const mutedAndBlockedChannelIds = Array.from(
new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1])) new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1]))
); );
const liveUris = [];
let streamTypesParam; let streamTypesParam;
if (streamTypes) { if (streamTypes) {
streamTypesParam = streamTypes; streamTypesParam = streamTypes;
@ -245,28 +164,16 @@ function ClaimTilesDiscover(props: Props) {
options.claim_ids = claimIds; options.claim_ids = claimIds;
} }
const mainSearchKey = createNormalizedClaimSearchKey(options); const searchKey = createNormalizedClaimSearchKey(options);
const livestreamSearchKey = liveLivestreamsFirst const isLoading = fetchingClaimSearchByQuery[searchKey];
? createNormalizedClaimSearchKey(getLivestreamOnlyOptions(options))
: undefined;
let uris = (prefixUris || []).concat(claimSearchByQuery[mainSearchKey] || []); let uris = (prefixUris || []).concat(claimSearchByQuery[searchKey] || []);
const isLoading = fetchingClaimSearchByQuery[mainSearchKey];
if (liveLivestreamsFirst && livestreamMap && !isLoading) {
prioritizeActiveLivestreams(uris, liveUris, livestreamMap, claimsByUri, claimSearchByQuery, options);
}
// Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time // Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time
const optionsStringForEffect = JSON.stringify(options); const optionsStringForEffect = JSON.stringify(options);
const shouldPerformSearch = !isLoading && uris.length === 0; const shouldPerformSearch = !isLoading && uris.length === 0;
if ( if (prefixUris === undefined && claimSearchByQuery[searchKey] === undefined) {
prefixUris === undefined &&
(claimSearchByQuery[mainSearchKey] === undefined ||
(livestreamSearchKey && claimSearchByQuery[livestreamSearchKey] === undefined))
) {
// This is a new query and we don't have results yet ... // This is a new query and we don't have results yet ...
if (prevUris.length !== 0) { if (prevUris.length !== 0) {
// ... but we have previous results. Use it until new results are here. // ... but we have previous results. Use it until new results are here.
@ -288,16 +195,6 @@ function ClaimTilesDiscover(props: Props) {
modifiedUris.splice(2, 0, ...fixUris); modifiedUris.splice(2, 0, ...fixUris);
} }
// **************************************************************************
// **************************************************************************
function resolveLive(index) {
if (liveLivestreamsFirst && livestreamMap && index < liveUris.length) {
return true;
}
return undefined;
}
function fetchViewCountForUris(uris) { function fetchViewCountForUris(uris) {
const claimIds = []; const claimIds = [];
@ -314,19 +211,12 @@ function ClaimTilesDiscover(props: Props) {
} }
} }
// **************************************************************************
// **************************************************************************
React.useEffect(() => { React.useEffect(() => {
if (shouldPerformSearch) { if (shouldPerformSearch) {
const searchOptions = JSON.parse(optionsStringForEffect); const searchOptions = JSON.parse(optionsStringForEffect);
doClaimSearch(searchOptions); doClaimSearch(searchOptions);
if (liveLivestreamsFirst) {
doClaimSearch(getLivestreamOnlyOptions(searchOptions));
} }
} }, [doClaimSearch, shouldPerformSearch, optionsStringForEffect]);
}, [doClaimSearch, shouldPerformSearch, optionsStringForEffect, liveLivestreamsFirst]);
React.useEffect(() => { React.useEffect(() => {
if (JSON.stringify(prevUris) !== JSON.stringify(uris) && !shouldPerformSearch) { if (JSON.stringify(prevUris) !== JSON.stringify(uris) && !shouldPerformSearch) {
@ -345,13 +235,12 @@ function ClaimTilesDiscover(props: Props) {
return ( return (
<ul className="claim-grid"> <ul className="claim-grid">
{modifiedUris && modifiedUris.length {modifiedUris && modifiedUris.length
? modifiedUris.map((uri, index) => ( ? modifiedUris.map((uri) => (
<ClaimPreviewTile <ClaimPreviewTile
showNoSourceClaims={hasNoSource || showNoSourceClaims} showNoSourceClaims={hasNoSource || showNoSourceClaims}
key={uri} key={uri}
uri={uri} uri={uri}
properties={renderProperties} properties={renderProperties}
live={resolveLive(index)}
/> />
)) ))
: new Array(pageSize) : new Array(pageSize)

View file

@ -9,7 +9,6 @@ import ClaimListDiscover from 'component/claimListDiscover';
import Page from 'component/page'; import Page from 'component/page';
import Button from 'component/button'; import Button from 'component/button';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import useGetLivestreams from 'effects/use-get-livestreams';
import { splitBySeparator } from 'lbry-redux'; import { splitBySeparator } from 'lbry-redux';
type Props = { type Props = {
@ -20,7 +19,6 @@ type Props = {
function ChannelsFollowingPage(props: Props) { function ChannelsFollowingPage(props: Props) {
const { subscribedChannels, tileLayout } = props; const { subscribedChannels, tileLayout } = props;
const hasSubsribedChannels = subscribedChannels.length > 0; const hasSubsribedChannels = subscribedChannels.length > 0;
const { livestreamMap } = useGetLivestreams();
return !hasSubsribedChannels ? ( return !hasSubsribedChannels ? (
<ChannelsFollowingDiscoverPage /> <ChannelsFollowingDiscoverPage />
@ -46,8 +44,6 @@ function ChannelsFollowingPage(props: Props) {
navigate={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`} navigate={`/$/${PAGES.CHANNELS_FOLLOWING_DISCOVER}`}
/> />
} }
liveLivestreamsFirst
livestreamMap={livestreamMap}
showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS} showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS}
hasSource hasSource
/> />

View file

@ -15,7 +15,6 @@ import Icon from 'component/common/icon';
import Ads from 'web/component/ads'; import Ads from 'web/component/ads';
import LbcSymbol from 'component/common/lbc-symbol'; import LbcSymbol from 'component/common/lbc-symbol';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import useGetLivestreams from 'effects/use-get-livestreams';
import moment from 'moment'; import moment from 'moment';
type Props = { type Props = {
@ -45,7 +44,6 @@ function DiscoverPage(props: Props) {
const buttonRef = useRef(); const buttonRef = useRef();
const isHovering = useHover(buttonRef); const isHovering = useHover(buttonRef);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { livestreamMap } = useGetLivestreams();
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const claimType = urlParams.get('claim_type'); const claimType = urlParams.get('claim_type');
@ -172,8 +170,6 @@ function DiscoverPage(props: Props) {
) )
) )
} }
liveLivestreamsFirst
livestreamMap={livestreamMap}
hasSource hasSource
showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS} showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS}
/> />

View file

@ -9,7 +9,6 @@ import ClaimTilesDiscover from 'component/claimTilesDiscover';
import ClaimPreviewTile from 'component/claimPreviewTile'; import ClaimPreviewTile from 'component/claimPreviewTile';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import WaitUntilOnPage from 'component/common/wait-until-on-page'; import WaitUntilOnPage from 'component/common/wait-until-on-page';
import useGetLivestreams from 'effects/use-get-livestreams';
import { GetLinksData } from 'util/buildHomepage'; import { GetLinksData } from 'util/buildHomepage';
// @if TARGET='web' // @if TARGET='web'
@ -30,7 +29,6 @@ function HomePage(props: Props) {
const showPersonalizedChannels = (authenticated || !IS_WEB) && subscribedChannels && subscribedChannels.length > 0; const showPersonalizedChannels = (authenticated || !IS_WEB) && subscribedChannels && subscribedChannels.length > 0;
const showPersonalizedTags = (authenticated || !IS_WEB) && followedTags && followedTags.length > 0; const showPersonalizedTags = (authenticated || !IS_WEB) && followedTags && followedTags.length > 0;
const showIndividualTags = showPersonalizedTags && followedTags.length < 5; const showIndividualTags = showPersonalizedTags && followedTags.length < 5;
const { livestreamMap } = useGetLivestreams();
const rowData: Array<RowDataItem> = GetLinksData( const rowData: Array<RowDataItem> = GetLinksData(
homepageData, homepageData,
@ -53,14 +51,7 @@ function HomePage(props: Props) {
</ul> </ul>
); );
const claimTiles = ( const claimTiles = (
<ClaimTilesDiscover <ClaimTilesDiscover {...options} showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS} hasSource pinUrls={pinUrls} />
{...options}
liveLivestreamsFirst
livestreamMap={livestreamMap}
showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS}
hasSource
pinUrls={pinUrls}
/>
); );
return ( return (

View file

@ -21,25 +21,6 @@ export function createNormalizedSearchKey(query: string) {
return normalizedQuery; return normalizedQuery;
} }
/**
* Returns the "livestream only" version of the given 'options'.
*
* Currently, the 'has_source' attribute is being used to identify livestreams.
*
* @param options
* @returns {*}
*/
export function getLivestreamOnlyOptions(options: any) {
const newOptions = Object.assign({}, options);
delete newOptions.has_source;
delete newOptions.stream_types;
newOptions.has_no_source = true;
newOptions.claim_type = ['stream'];
newOptions.page_size = 50;
newOptions.order_by = ['release_time'];
return newOptions;
}
/** /**
* getUriForSearchTerm * getUriForSearchTerm
* @param term * @param term