@streamlayer/feature-advertisement 0.2.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/advertisement.d.ts +5 -0
- package/lib/advertisement.js +32 -2
- package/lib/index.d.ts +2 -1
- package/lib/units/external-ad.d.ts +19 -0
- package/lib/units/external-ad.js +83 -0
- package/package.json +6 -6
package/lib/advertisement.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { AbstractFeatureUnit, StreamLayerContext } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { externalAd, type ExternalAdOptions } from './units/external-ad';
|
|
2
3
|
import { externalPauseAd, type ExternalPauseAdOptions } from './units/external-pause-ad';
|
|
4
|
+
export type ExternalAdStore = ReturnType<ReturnType<typeof externalAd>>;
|
|
3
5
|
export type ExternalPauseAdStore = ReturnType<ReturnType<typeof externalPauseAd>>;
|
|
4
6
|
export declare class Advertisement extends AbstractFeatureUnit {
|
|
7
|
+
getExternalAd: (adUrl: string, options: ExternalAdOptions) => [ExternalAdStore, string];
|
|
5
8
|
getExternalPauseAd: (adUrl: string, options: ExternalPauseAdOptions) => [ExternalPauseAdStore, string];
|
|
9
|
+
private externalAdStores;
|
|
10
|
+
private externalAdEnabled;
|
|
6
11
|
private externalPauseAdStores;
|
|
7
12
|
private externalPauseAdEnabled;
|
|
8
13
|
private log;
|
package/lib/advertisement.js
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
import { AbstractFeatureUnit, createSingleStore } from '@streamlayer/sdk-web-interfaces';
|
|
2
2
|
import { createLogger } from '@streamlayer/sdk-web-logger';
|
|
3
|
+
import { externalAd } from './units/external-ad';
|
|
3
4
|
import { externalPauseAd } from './units/external-pause-ad';
|
|
4
5
|
export class Advertisement extends AbstractFeatureUnit {
|
|
6
|
+
getExternalAd;
|
|
5
7
|
getExternalPauseAd;
|
|
8
|
+
externalAdStores = new Map();
|
|
9
|
+
externalAdEnabled = new Map();
|
|
6
10
|
externalPauseAdStores = new Map();
|
|
7
11
|
externalPauseAdEnabled = new Map();
|
|
8
12
|
log;
|
|
9
13
|
constructor(instance) {
|
|
10
14
|
super();
|
|
11
15
|
this.log = createLogger('advertisement');
|
|
16
|
+
const externalAdGenerator = externalAd(instance);
|
|
12
17
|
const externalPauseAdGenerator = externalPauseAd(instance);
|
|
18
|
+
this.getExternalAd = (adUrl, options) => {
|
|
19
|
+
if (this.externalAdStores.has(adUrl)) {
|
|
20
|
+
const $enabled = this.externalAdEnabled.get(adUrl);
|
|
21
|
+
const $store = this.externalAdStores.get(adUrl);
|
|
22
|
+
const shouldRevalidate = $enabled.get() === false && options.$enabled === true;
|
|
23
|
+
$enabled.set(options.$enabled);
|
|
24
|
+
if (shouldRevalidate) {
|
|
25
|
+
window.requestAnimationFrame(() => {
|
|
26
|
+
$store.revalidate();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return [$store, adUrl];
|
|
30
|
+
}
|
|
31
|
+
const $enabled = createSingleStore(options.$enabled);
|
|
32
|
+
const store = externalAdGenerator(adUrl, $enabled, options);
|
|
33
|
+
this.externalAdEnabled.set(adUrl, $enabled);
|
|
34
|
+
this.externalAdStores.set(adUrl, store);
|
|
35
|
+
return [store, adUrl];
|
|
36
|
+
};
|
|
13
37
|
this.getExternalPauseAd = (adUrl, options) => {
|
|
14
38
|
if (this.externalPauseAdStores.has(adUrl)) {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
16
39
|
const $enabled = this.externalPauseAdEnabled.get(adUrl);
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
18
40
|
const $store = this.externalPauseAdStores.get(adUrl);
|
|
19
41
|
const shouldRevalidate = $enabled.get() === false && options.$enabled === true;
|
|
20
42
|
$enabled.set(options.$enabled);
|
|
@@ -37,6 +59,14 @@ export class Advertisement extends AbstractFeatureUnit {
|
|
|
37
59
|
};
|
|
38
60
|
disconnect = () => {
|
|
39
61
|
this.log.debug('disconnect');
|
|
62
|
+
this.externalAdStores.forEach((store) => {
|
|
63
|
+
store.off();
|
|
64
|
+
});
|
|
65
|
+
this.externalAdEnabled.forEach((enabled) => {
|
|
66
|
+
enabled.off();
|
|
67
|
+
});
|
|
68
|
+
this.externalAdEnabled.clear();
|
|
69
|
+
this.externalAdStores.clear();
|
|
40
70
|
this.externalPauseAdStores.forEach((store) => {
|
|
41
71
|
store.off();
|
|
42
72
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare module '@streamlayer/sdk-web-interfaces' {
|
|
|
4
4
|
advertisement: import('./advertisement').Advertisement;
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
export { type ExternalPauseAdStore } from './advertisement';
|
|
7
|
+
export { type ExternalAdStore, type ExternalPauseAdStore } from './advertisement';
|
|
8
|
+
export { type GAMStaticAdCore } from './units/external-ad';
|
|
8
9
|
export { type GAMStaticCore } from './units/external-pause-ad';
|
|
9
10
|
export declare const advertisement: (instance: StreamLayerContext, _opts: unknown, done: () => void) => void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createSingleStore, StreamLayerContext } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import '@streamlayer/sdk-web-api';
|
|
3
|
+
export type GAMStaticAdCore = {
|
|
4
|
+
id: string;
|
|
5
|
+
parentId: string;
|
|
6
|
+
url: string;
|
|
7
|
+
imageSrc?: string;
|
|
8
|
+
videoSrc?: string;
|
|
9
|
+
sponsorSrc?: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
adUrl?: string;
|
|
13
|
+
};
|
|
14
|
+
export type ExternalAdOptions = {
|
|
15
|
+
refetchInterval: number;
|
|
16
|
+
prefetch: boolean;
|
|
17
|
+
$enabled: boolean;
|
|
18
|
+
};
|
|
19
|
+
export declare const externalAd: (instance: StreamLayerContext) => (gamUrl: string, $enabled: ReturnType<typeof createSingleStore<boolean>>, options: ExternalAdOptions) => import("@nanostores/query").FetcherStore<GAMStaticAdCore | undefined, any>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createLogger } from '@streamlayer/sdk-web-logger';
|
|
2
|
+
import '@streamlayer/sdk-web-api';
|
|
3
|
+
import { VASTClient } from '@dailymotion/vast-client';
|
|
4
|
+
const vastClient = new VASTClient();
|
|
5
|
+
const log = createLogger('ui:gam-static-ad');
|
|
6
|
+
const preloadImage = (src) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const image = new Image();
|
|
9
|
+
image.onload = () => resolve(src);
|
|
10
|
+
image.onerror = () => reject();
|
|
11
|
+
image.src = src;
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
export const externalAd = (instance) => {
|
|
15
|
+
return (gamUrl, $enabled, options) => instance.transport.nanoquery.createFetcherStore([gamUrl, $enabled], {
|
|
16
|
+
dedupeTime: options.prefetch ? options.refetchInterval : Infinity,
|
|
17
|
+
revalidateInterval: options.refetchInterval > 0 ? options.refetchInterval : 0,
|
|
18
|
+
fetcher: async (adUrl) => {
|
|
19
|
+
if (!adUrl || typeof adUrl !== 'string') {
|
|
20
|
+
throw new Error('ad url is empty');
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const parsedVAST = await vastClient.get(adUrl);
|
|
24
|
+
const validAd = parsedVAST.ads.find((ads) => ads.creatives.length > 0);
|
|
25
|
+
if (validAd) {
|
|
26
|
+
const parentId = validAd.id || '';
|
|
27
|
+
const store = {
|
|
28
|
+
id: '',
|
|
29
|
+
parentId,
|
|
30
|
+
url: adUrl,
|
|
31
|
+
title: validAd.title || '',
|
|
32
|
+
description: validAd.description || '',
|
|
33
|
+
};
|
|
34
|
+
log.debug(validAd, 'validAd');
|
|
35
|
+
const linear = validAd.creatives.find((creative) => creative.type === 'linear');
|
|
36
|
+
if (linear) {
|
|
37
|
+
store.id = linear.adId || linear.id || parentId;
|
|
38
|
+
log.debug(linear, 'linear');
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
store.videoSrc = linear.mediaFiles?.find((mediaFile) => !!mediaFile.fileURL)?.fileURL;
|
|
42
|
+
}
|
|
43
|
+
const nonlinear = validAd.creatives.find((creative) => creative.type === 'nonlinear');
|
|
44
|
+
if (nonlinear) {
|
|
45
|
+
store.id = nonlinear.adId || nonlinear.id || parentId;
|
|
46
|
+
log.debug(nonlinear, 'nonlinear');
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
const staticResource = nonlinear.variations?.[0]?.staticResource;
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
store.adUrl = nonlinear.variations?.[0]?.nonlinearClickThroughURLTemplate;
|
|
53
|
+
if (staticResource) {
|
|
54
|
+
await preloadImage(staticResource);
|
|
55
|
+
store.imageSrc = staticResource;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const companion = validAd.creatives.find((creative) => creative.type === 'companion');
|
|
59
|
+
log.debug(companion, 'companion');
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
const staticResource = companion?.variations?.[0]?.staticResources?.[0]?.url;
|
|
63
|
+
if (staticResource) {
|
|
64
|
+
await preloadImage(staticResource);
|
|
65
|
+
store.sponsorSrc = staticResource;
|
|
66
|
+
}
|
|
67
|
+
if (store.imageSrc || store.videoSrc) {
|
|
68
|
+
return store;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
throw new Error('no_valid_ad');
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
75
|
+
// @ts-expect-error
|
|
76
|
+
if (err.message !== 'no_valid_ad' && err.message !== 'ad url is empty') {
|
|
77
|
+
console.error(err);
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamlayer/feature-advertisement",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@dailymotion/vast-client": "^6.4.2",
|
|
6
6
|
"@streamlayer/sl-eslib": "^5.229.1",
|
|
7
7
|
"nanostores": "^1.1.0",
|
|
8
|
-
"@streamlayer/sdk-web-core": "^1.
|
|
9
|
-
"@streamlayer/sdk-web-api": "^1.
|
|
10
|
-
"@streamlayer/sdk-web-interfaces": "^1.
|
|
11
|
-
"@streamlayer/sdk-web-types": "^1.
|
|
12
|
-
"@streamlayer/sdk-web-logger": "^1.
|
|
8
|
+
"@streamlayer/sdk-web-core": "^1.22.1",
|
|
9
|
+
"@streamlayer/sdk-web-api": "^1.17.1",
|
|
10
|
+
"@streamlayer/sdk-web-interfaces": "^1.10.1",
|
|
11
|
+
"@streamlayer/sdk-web-types": "^1.18.1",
|
|
12
|
+
"@streamlayer/sdk-web-logger": "^1.1.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/vast-client": "^3.0.4"
|