kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Support x-truth-ad-indexes header
rodzic
d19a93f109
commit
f1a4b87dd9
|
@ -2,6 +2,7 @@ import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutabl
|
|||
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { normalizeStatus } from 'soapbox/normalizers';
|
||||
import { adIndexesFromHeader } from 'soapbox/utils/ads';
|
||||
import { shouldFilter } from 'soapbox/utils/timelines';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
@ -172,8 +173,9 @@ const expandTimeline = (timelineId: string, path: string, params: Record<string,
|
|||
|
||||
return api(getState).get(path, { params }).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const adIndexes = adIndexesFromHeader(response);
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.status === 206, isLoadingRecent, isLoadingMore));
|
||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.status === 206, isLoadingRecent, isLoadingMore, adIndexes));
|
||||
done();
|
||||
}).catch(error => {
|
||||
dispatch(expandTimelineFail(timelineId, error, isLoadingMore));
|
||||
|
@ -234,7 +236,15 @@ const expandTimelineRequest = (timeline: string, isLoadingMore: boolean) => ({
|
|||
skipLoading: !isLoadingMore,
|
||||
});
|
||||
|
||||
const expandTimelineSuccess = (timeline: string, statuses: APIEntity[], next: string | null, partial: boolean, isLoadingRecent: boolean, isLoadingMore: boolean) => ({
|
||||
const expandTimelineSuccess = (
|
||||
timeline: string,
|
||||
statuses: APIEntity[],
|
||||
next: string | null,
|
||||
partial: boolean,
|
||||
isLoadingRecent: boolean,
|
||||
isLoadingMore: boolean,
|
||||
adIndexes: number[],
|
||||
) => ({
|
||||
type: TIMELINE_EXPAND_SUCCESS,
|
||||
timeline,
|
||||
statuses,
|
||||
|
@ -242,6 +252,7 @@ const expandTimelineSuccess = (timeline: string, statuses: APIEntity[], next: st
|
|||
partial,
|
||||
isLoadingRecent,
|
||||
skipLoading: !isLoadingMore,
|
||||
adIndexes,
|
||||
});
|
||||
|
||||
const expandTimelineFail = (timeline: string, error: AxiosError, isLoadingMore: boolean) => ({
|
||||
|
|
|
@ -13,7 +13,7 @@ import FeedSuggestions from 'soapbox/features/feed-suggestions/feed-suggestions'
|
|||
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
||||
import { ALGORITHMS } from 'soapbox/features/timeline-insertion';
|
||||
import PendingStatus from 'soapbox/features/ui/components/pending_status';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
|
||||
import useAds from 'soapbox/queries/ads';
|
||||
|
||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
@ -66,6 +66,7 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
|
||||
const adsAlgorithm = String(soapboxConfig.extensions.getIn(['ads', 'algorithm', 0]));
|
||||
const adsOpts = (soapboxConfig.extensions.getIn(['ads', 'algorithm', 1], ImmutableMap()) as ImmutableMap<string, any>).toJS();
|
||||
const adIndexes = useAppSelector(state => state.timelines.getIn([timelineId, 'adIndexes'], [[]]) as readonly number[][]);
|
||||
|
||||
const node = useRef<VirtuosoHandle>(null);
|
||||
const seed = useRef<string>(uuidv4());
|
||||
|
@ -177,12 +178,23 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
|
||||
const renderStatuses = (): React.ReactNode[] => {
|
||||
if (isLoading || statusIds.size > 0) {
|
||||
let lastAdIndex = 0;
|
||||
return statusIds.toList().reduce((acc, statusId, index) => {
|
||||
if (showAds && ads) {
|
||||
const ad = ALGORITHMS[adsAlgorithm]?.(ads, index, { ...adsOpts, seed: seed.current });
|
||||
if ((adIndexes[Math.floor(index / 20)] || []).includes(index)) {
|
||||
const ad = ads[lastAdIndex % ads.length];
|
||||
|
||||
if (ad) {
|
||||
acc.push(renderAd(ad, index));
|
||||
if (ad) {
|
||||
acc.push(renderAd(ad, index));
|
||||
}
|
||||
|
||||
lastAdIndex++;
|
||||
} else {
|
||||
const ad = ALGORITHMS[adsAlgorithm]?.(ads, index, { ...adsOpts, seed: seed.current });
|
||||
|
||||
if (ad) {
|
||||
acc.push(renderAd(ad, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ const TestTimeline: React.FC = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
dispatch(importFetchedStatuses(MOCK_STATUSES));
|
||||
dispatch(expandTimelineSuccess(timelineId, MOCK_STATUSES, null, false, false, false));
|
||||
dispatch(expandTimelineSuccess(timelineId, MOCK_STATUSES, null, false, false, false, []));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
@ -3,7 +3,7 @@ import { linearAlgorithm } from './linear';
|
|||
|
||||
import type { PickAlgorithm } from './types';
|
||||
|
||||
const ALGORITHMS: Record<any, PickAlgorithm | undefined> = {
|
||||
const ALGORITHMS: Record<string, PickAlgorithm | undefined> = {
|
||||
'linear': linearAlgorithm,
|
||||
'abovefold': abovefoldAlgorithm,
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@ const TimelineRecord = ImmutableRecord({
|
|||
totalQueuedItemsCount: 0, //used for queuedItems overflow for MAX_QUEUED_ITEMS+
|
||||
loadingFailed: false,
|
||||
isPartial: false,
|
||||
adIndexes: [] as readonly number[][],
|
||||
});
|
||||
|
||||
const initialState = ImmutableMap<string, Timeline>();
|
||||
|
@ -88,7 +89,7 @@ const setFailed = (state: State, timelineId: string, failed: boolean) => {
|
|||
return state.update(timelineId, TimelineRecord(), timeline => timeline.set('loadingFailed', failed));
|
||||
};
|
||||
|
||||
const expandNormalizedTimeline = (state: State, timelineId: string, statuses: ImmutableList<ImmutableMap<string, any>>, next: string | null, isPartial: boolean, isLoadingRecent: boolean) => {
|
||||
const expandNormalizedTimeline = (state: State, timelineId: string, statuses: ImmutableList<ImmutableMap<string, any>>, next: string | null, isPartial: boolean, isLoadingRecent: boolean, adIndexes: number[]) => {
|
||||
const newIds = getStatusIds(statuses);
|
||||
|
||||
return state.update(timelineId, TimelineRecord(), timeline => timeline.withMutations(timeline => {
|
||||
|
@ -96,6 +97,10 @@ const expandNormalizedTimeline = (state: State, timelineId: string, statuses: Im
|
|||
timeline.set('loadingFailed', false);
|
||||
timeline.set('isPartial', isPartial);
|
||||
|
||||
timeline.update('adIndexes', (oldAdIndexes: readonly number[][]) => {
|
||||
return [...oldAdIndexes, [...adIndexes]];
|
||||
});
|
||||
|
||||
if (!next && !isLoadingRecent) timeline.set('hasMore', false);
|
||||
|
||||
// Pinned timelines can be replaced entirely
|
||||
|
@ -321,7 +326,7 @@ export default function timelines(state: State = initialState, action: AnyAction
|
|||
case TIMELINE_EXPAND_FAIL:
|
||||
return handleExpandFail(state, action.timeline);
|
||||
case TIMELINE_EXPAND_SUCCESS:
|
||||
return expandNormalizedTimeline(state, action.timeline, fromJS(action.statuses) as ImmutableList<ImmutableMap<string, any>>, action.next, action.partial, action.isLoadingRecent);
|
||||
return expandNormalizedTimeline(state, action.timeline, fromJS(action.statuses) as ImmutableList<ImmutableMap<string, any>>, action.next, action.partial, action.isLoadingRecent, action.adIndexes);
|
||||
case TIMELINE_UPDATE:
|
||||
return updateTimeline(state, action.timeline, action.statusId);
|
||||
case TIMELINE_UPDATE_QUEUE:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { AxiosResponse } from 'axios';
|
||||
import type { Ad } from 'soapbox/types/soapbox';
|
||||
|
||||
/** Time (ms) window to not display an ad if it's about to expire. */
|
||||
|
@ -13,4 +14,14 @@ const isExpired = (ad: Ad, threshold = AD_EXPIRY_THRESHOLD): boolean => {
|
|||
}
|
||||
};
|
||||
|
||||
export { isExpired };
|
||||
/** Get ad indexes from X-Truth-Ad-Indexes header. */
|
||||
const adIndexesFromHeader = (response: AxiosResponse): number[] => {
|
||||
const header: string = response.headers['x-truth-ad-indexes'];
|
||||
const strIndexes: string[] = header.split(',');
|
||||
return strIndexes.map(strIndex => Number(strIndex.trim()));
|
||||
};
|
||||
|
||||
export {
|
||||
isExpired,
|
||||
adIndexesFromHeader,
|
||||
};
|
||||
|
|
Ładowanie…
Reference in New Issue