Skip to content

Commit

Permalink
chore(project): ad-config + media ads
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonLantukh committed Oct 31, 2023
1 parent c943268 commit c2e1d66
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 173 deletions.
23 changes: 6 additions & 17 deletions src/components/Player/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +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';
import { useAds } from '#src/hooks/useAds';

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

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 { adSchedule, adScheduleUrls } = useConfigStore((s) => s.config);
const { data: adsData, isLoading: isAdsLoading } = useAds(adSchedule, adScheduleUrls, item?.mediaid);

const handleBeforePlay = useEventCallback(onBeforePlay);
const handlePlay = useEventCallback(onPlay);
Expand Down Expand Up @@ -162,19 +161,9 @@ const Player: React.FC<Props> = ({

playerRef.current = window.jwplayer(playerElementRef.current) as JWPlayer;

const data = {
...adScheduleData,
schedule: adScheduleData.schedule.map((el) => ({ ...el, offset: el.offset / 1000 })),
client: 'googima',
vpaidmode: 'insecure',
rules: { startOnSeek: 'pre', timeBetweenAds: 0 },
};

console.log(data, 'data');

// Player options are untyped
const playerOptions: { [key: string]: unknown } = {
advertising: data,
advertising: adsData,
aspectratio: false,
controls: true,
displaytitle: false,
Expand Down Expand Up @@ -214,10 +203,10 @@ const Player: React.FC<Props> = ({
return loadPlaylist();
}

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

useEffect(() => {
return () => {
Expand Down
22 changes: 0 additions & 22 deletions src/hooks/useAdSchedule.ts

This file was deleted.

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

import { getMediaAds, getAdSchedule } from '#src/services/api.service';
import type { AdScheduleUrls } from '#types/ad-schedule';

const CACHE_TIME = 60 * 1000 * 20;

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

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

return {
isLoading,
data,
};
};

const useMediaAds = (jsonUrl: string | null | undefined, mediaId: string, enabled: boolean) => {
const { isLoading, data } = useQuery(
['media-ads', mediaId],
async () => {
// Waiting for `prd` deploy to remove `replace`
const mediaAds = await getMediaAds(jsonUrl?.replace('advertising/site', 'sites') as string, mediaId);

return mediaAds;
},
{ enabled, cacheTime: CACHE_TIME, staleTime: CACHE_TIME },
);

return {
isLoading,
data,
};
};

export const useAds = (adScheduleId: string | null | undefined, urls: AdScheduleUrls | undefined, mediaId: string) => {
const hasAdConfig = !!urls?.json;

// Fetch ad-schedule only when ad-config is not set (`adScheduleUrls.json` prop is not set) + adScheduleId is present
const { data: adSchedule, isLoading: isAdScheduleLoading } = useAdSchedule(adScheduleId, !!(adScheduleId && hasAdConfig));
// adScheduleUrls.json prop exists when ad-config is attached to the App Config
const { isLoading: isMediaAdsLoading, data: mediaAds } = useMediaAds(urls?.json, mediaId, hasAdConfig);

return {
isLoading: isAdScheduleLoading || isMediaAdsLoading,
data: mediaAds || adSchedule,
};
};
28 changes: 0 additions & 28 deletions src/hooks/useMediaAds.ts

This file was deleted.

104 changes: 6 additions & 98 deletions 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, AdTagUrls } from '#types/ad-schedule';
import type { AdSchedule } 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 @@ -243,112 +243,20 @@ export const getAdSchedule = async (id: string | undefined | null): Promise<AdSc
}

const url = import.meta.env.APP_API_BASE_URL + `/v2/advertising/schedules/${id}.json`;
const response = await fetch(url);
const response = await fetch(url, { credentials: 'omit' });
const data = await getDataOrThrow(response);

return data;
};

export const getMediaAdSchedule = async (id: string, urls: AdTagUrls, fallbackAdSchedule: string | undefined | null): Promise<AdSchedule | undefined> => {
const { preRollUrl, midRollUrl, postRollUrl } = urls;
const pathname = `/v1/advertising/media/${id}/schedule.json`;
const url = addQueryParams(`https://timing-delivery.jwplayer.com${pathname}`, {
preroll_url: preRollUrl,
midroll_url: midRollUrl || 'https://playertest.longtailvideo.com/vast-30s-ad.xml',
postroll_url: postRollUrl,
fallback_ad_schedule: fallbackAdSchedule,
export const getMediaAds = async (url: string, mediaId: string): Promise<AdSchedule | undefined> => {
const urlWithQuery = addQueryParams(url, {
media_id: mediaId,
});

const response = await fetch(url);

// No media ads set up
if (response.status === 204) {
return;
}
const response = await fetch(urlWithQuery, { credentials: 'omit' });

const data = (await getDataOrThrow(response)) as AdSchedule;

return data;
};

const advertising = {
rules: {
startOnSeek: 'pre',
timeBetweenAds: 0,
},
client: 'googima',
schedule: [
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 9,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 21,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 41,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 65,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 88,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 103,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 127,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 154,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 181,
},
{
tag: [
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
],
type: 'linear',
offset: 212,
},
],
adscheduleid: 'p7C1mlvt',
vpaidmode: 'insecure',
};
4 changes: 4 additions & 0 deletions src/services/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const configSchema: SchemaOf<Config> = object({
description: string().defined(),
analyticsToken: string().nullable(),
adSchedule: string().nullable(),
adScheduleUrls: object({
json: string().notRequired().nullable(),
xml: string().notRequired().nullable(),
}).notRequired(),
assets: object({
banner: string().notRequired().nullable(),
}).notRequired(),
Expand Down
4 changes: 3 additions & 1 deletion types/Config.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import type { AdScheduleUrls } from '#types/ad-schedule';

/**
* Set config setup changes in both config.services.ts and config.d.ts
* */

export type Config = {
id?: string;
siteName?: string;
description: string;
analyticsToken?: string | null;
adSchedule?: string | null;
adScheduleUrls?: AdScheduleUrls;
integrations: {
cleeng?: Cleeng;
jwp?: JWP;
Expand Down
7 changes: 3 additions & 4 deletions types/ad-schedule.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ export type AdSchedule = {
schedule: string;
};

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

Expand Down

0 comments on commit c2e1d66

Please sign in to comment.