Skip to content

Commit

Permalink
feat(project): per media ads
Browse files Browse the repository at this point in the history
- add per media ads functionality
  • Loading branch information
AntonLantukh committed Sep 15, 2023
1 parent be3c907 commit f27283e
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/components/Player/Player.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { render } from '@testing-library/react';

import Player from './Player';

import type { PlaylistItem } from '#types/playlist';
import { renderWithRouter } from '#test/testUtils';

describe('<Player>', () => {
test('renders and matches snapshot', () => {
Expand All @@ -24,7 +24,7 @@ describe('<Player>', () => {
title: 'Test item title',
tracks: [],
} as PlaylistItem;
const { container } = render(<Player playerId="123456" playerLicenseKey="testkey" item={item} onPlay={() => null} onPause={() => null} />);
const { container } = renderWithRouter(<Player playerId="123456" playerLicenseKey="testkey" item={item} onPlay={() => null} onPause={() => null} />);

expect(container).toMatchSnapshot();
});
Expand Down
9 changes: 6 additions & 3 deletions src/components/Player/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useEventCallback from '#src/hooks/useEventCallback';
import useOttAnalytics from '#src/hooks/useOttAnalytics';
import { logDev, testId } from '#src/utils/common';
import { useConfigStore } from '#src/stores/ConfigStore';
import { useMediaAds } from '#src/hooks/useMediaAds';

type Props = {
playerId: string;
Expand Down Expand Up @@ -59,7 +60,9 @@ const Player: React.FC<Props> = ({
const startTimeRef = useRef(startTime);
const setPlayer = useOttAnalytics(item, feedId);

const { adScheduleData } = useConfigStore((s) => s);
const adScheduleId = useConfigStore((s) => s.config.adSchedule);
const { preRollUrl, midRollUrl, postRollUrl } = item;
const { data: adScheduleData, isLoading: isAdScheduleLoading } = useMediaAds(adScheduleId, item?.mediaid, { preRollUrl, midRollUrl, postRollUrl });

const handleBeforePlay = useEventCallback(onBeforePlay);
const handlePlay = useEventCallback(onPlay);
Expand Down Expand Up @@ -201,10 +204,10 @@ const Player: React.FC<Props> = ({
return loadPlaylist();
}

if (libLoaded) {
if (libLoaded && !isAdScheduleLoading) {
initializePlayer();
}
}, [libLoaded, item, detachEvents, attachEvents, playerId, setPlayer, autostart, adScheduleData, playerLicenseKey, feedId]);
}, [libLoaded, item, detachEvents, attachEvents, playerId, setPlayer, autostart, adScheduleData, playerLicenseKey, feedId, isAdScheduleLoading]);

useEffect(() => {
return () => {
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/useAdSchedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useQuery } from 'react-query';

import { getAdSchedule } from '#src/services/api.service';

const CACHE_TIME = 60 * 1000 * 60 * 8;

export const useAdSchedule = (adScheduleId: string | null | undefined) => {
const { isLoading, data } = useQuery(
['ad-schedule'],
async () => {
const adSchedule = await getAdSchedule(adScheduleId);

return adSchedule;
},
{ enabled: Boolean(adScheduleId), cacheTime: CACHE_TIME, staleTime: CACHE_TIME },
);

return {
isLoading,
data,
};
};
25 changes: 25 additions & 0 deletions src/hooks/useMediaAds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useQuery } from 'react-query';

import { getMediaAdSchedule } from '#src/services/api.service';
import { useAdSchedule } from '#src/hooks/useAdSchedule';
import type { AdTagUrls } from '#types/ad-schedule';

// 204 code
export const useMediaAds = (adScheduleId: string | null | undefined, mediaId: string, urls: AdTagUrls) => {
const { data: adSchedule, isLoading: isAdScheduleLoading } = useAdSchedule(adScheduleId);

const { isLoading: isPerMediaAdSchedule, data: perMediaAds } = useQuery(
['per-media-ad-schedule', mediaId],
async () => {
const adSchedule = await getMediaAdSchedule(mediaId, urls, adScheduleId);

return adSchedule;
},
{ enabled: Boolean(mediaId) },
);

return {
isLoading: isAdScheduleLoading || isPerMediaAdSchedule,
data: perMediaAds || adSchedule,
};
};
25 changes: 24 additions & 1 deletion src/services/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { addQueryParams } from '#src/utils/formatting';
import { getDataOrThrow } from '#src/utils/api';
import { filterMediaOffers } from '#src/utils/entitlements';
import type { GetPlaylistParams, Playlist, PlaylistItem } from '#types/playlist';
import type { AdSchedule } from '#types/ad-schedule';
import type { AdSchedule, AdTagUrls } from '#types/ad-schedule';
import type { EpisodesRes, EpisodesWithPagination, GetSeriesParams, Series, EpisodeInSeries } from '#types/series';
import { useConfigStore as ConfigStore } from '#src/stores/ConfigStore';

Expand Down Expand Up @@ -92,6 +92,7 @@ export const getPlaylistById = async (id?: string, params: GetPlaylistParams = {
/**
* Get watchlist by playlistId
* @param {string} playlistId
* @param {string[]} mediaIds
* @param {string} [token]
*/
export const getMediaByWatchlist = async (playlistId: string, mediaIds: string[], token?: string): Promise<PlaylistItem[] | undefined> => {
Expand Down Expand Up @@ -247,3 +248,25 @@ export const getAdSchedule = async (id: string | undefined | null): Promise<AdSc

return data;
};

export const getMediaAdSchedule = async (id: string, urls: AdTagUrls, fallbackAdSchedule: string | undefined | null): Promise<AdSchedule | undefined> => {
const { preRollUrl, midRollUrl, postRollUrl } = urls;
const pathname = `/v2/advertising/media/${id}/schedule.json`;
const url = addQueryParams(`${import.meta.env.APP_API_BASE_URL}${pathname}`, {
preroll_url: preRollUrl,
midroll_url: midRollUrl,
postroll_url: postRollUrl,
fallback_ad_schedule: fallbackAdSchedule,
});

const response = await fetch(url);

// No media ads set up
if (response.status === 204) {
return;
}

const data = (await getDataOrThrow(response)) as { timings: AdSchedule };

return data.timings;
};
6 changes: 6 additions & 0 deletions types/ad-schedule.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ export type AdSchedule = {
client: string;
schedule: string;
};

export type AdTagUrls = {
preRollUrl: string | undefined;
midRollUrl: string | undefined;
postRollUrl: string | undefined;
};
3 changes: 3 additions & 0 deletions types/playlist.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export type PlaylistItem = {
scheduledStart?: Date;
scheduledEnd?: Date;
markdown?: string;
preRollUrl?: string;
midRollUrl?: string;
postRollUrl?: string;
[key: string]: unknown;
};

Expand Down

0 comments on commit f27283e

Please sign in to comment.