From ed958fd2db8295a18500bba59fb75883eb92fce0 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:30:17 +0200 Subject: [PATCH 01/59] types --- adscript/src/adscript/AdScript.d.ts | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 adscript/src/adscript/AdScript.d.ts diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts new file mode 100644 index 00000000..59b42148 --- /dev/null +++ b/adscript/src/adscript/AdScript.d.ts @@ -0,0 +1,76 @@ +export type JHMTApiProtocol = "https:" | "http:" | "file:" +interface I12n { + i1: string; + i2: string; + i3: string; + i4: string; + i5: string; +} + +export type MainVideoContentType = "content" +export type EmbeddedContentType = "preroll" | "midroll" | "postroll" +export type StaticContentType = "static" + +export interface MainVideoContentMetadata { + assetid: string; + type: MainVideoContentType; + program: string; + title: string; + length: string; + crossId: string; + livestream: string; + channelId: string; + attributes: string; +} + +interface EmbeddedContentMetadata { + assetid: string; + type: EmbeddedContentType; + length: string; + title: string; + asmea: string; + attributes: string; +} + + +interface StaticContentMetadata { + assetid: string; + type: MainVideoContentType; + sec1: string; + sec2: string; + sec3: string; + sec4: string; + ref: string; +} + +export interface PlayerState { + muted: number; + volume: number; + triggeredByUser: number; + normalSpeed: number; + fullscreen: number; + visibility: number; + width: number; + height: number; +} + +interface JHMTArray extends Array { + i12n: I12n; + contentMetadata: ContentMetadata; + playerState: PlayerState; + push: (item: any) => number; // Type of the push function +} + +declare global { + interface Window { + JHMT: JHMTArray; + JHMTApi: typeof JHMTApi; + JHMTApiProtocol: JHMTApiProtocol + } +} + +export interface JHMTApi { + setI12n(i12n: I12n); + setContentMetadata(contentMetadata: ContentMetadata); + setPlayerState(playerState: PlayerState); +} \ No newline at end of file From bc7e8ca1b05ee0fbc49a141d4b2bbf0fc5762938 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:31:03 +0200 Subject: [PATCH 02/59] initial implementation --- adscript/src/index.ts | 3 + .../src/integration/AdScriptConfiguration.ts | 8 + adscript/src/integration/AdScriptConnector.ts | 35 +++ .../integration/AdScriptTHEOIntegration.ts | 279 ++++++++++++++++++ adscript/src/utils/Logger.ts | 26 ++ 5 files changed, 351 insertions(+) create mode 100644 adscript/src/index.ts create mode 100644 adscript/src/integration/AdScriptConfiguration.ts create mode 100644 adscript/src/integration/AdScriptConnector.ts create mode 100644 adscript/src/integration/AdScriptTHEOIntegration.ts create mode 100644 adscript/src/utils/Logger.ts diff --git a/adscript/src/index.ts b/adscript/src/index.ts new file mode 100644 index 00000000..ec58a5f5 --- /dev/null +++ b/adscript/src/index.ts @@ -0,0 +1,3 @@ +export { AdScriptConnector } from './integration/AdScriptConnector'; +export * from './integration/AdScriptConfiguration' +// export * from './api/path/to/typing/helpers/etc'; diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts new file mode 100644 index 00000000..87fbe31e --- /dev/null +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -0,0 +1,8 @@ +import { Ad } from "theoplayer"; +import { EmbeddedContentMetadata } from "../adscript/AdScript"; + +export interface AdScriptConfiguration { + implementationId: string; + debug?: boolean; + adProcessor?: (ad: Ad) => EmbeddedContentMetadata +} \ No newline at end of file diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts new file mode 100644 index 00000000..78c72085 --- /dev/null +++ b/adscript/src/integration/AdScriptConnector.ts @@ -0,0 +1,35 @@ +import { ChromelessPlayer } from 'theoplayer'; +import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; +import { AdScriptConfiguration } from './AdScriptConfiguration'; +import { MainVideoContentMetadata } from '../adscript/AdScript'; + +export class AdScriptConnector { + + private adscriptIntegration: AdScriptTHEOIntegration | undefined; + + /** + * Constructor for the THEOplayer AdScript connector + * @param player a THEOplayer instance reference + * @param configuration a configuration object for the AdScript connector + * @returns + */ + constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { + if (!window.JHMTApi || !window.JHMT) { + console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement') + return; + } + this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata) + } + + updateMetadata(metadata: any): void { + this.adscriptIntegration?.updateMetadata(metadata) + } + + + /** + * Destroy + */ + destroy(): void { + this.adscriptIntegration?.destroy() + } +} \ No newline at end of file diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts new file mode 100644 index 00000000..35876c59 --- /dev/null +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -0,0 +1,279 @@ +import { + Ad, + AdBreakEvent, + AdEvent, + ChromelessPlayer, + DurationChangeEvent, + EndedEvent, + Event, + GoogleImaAd, + PlayEvent, + RateChangeEvent, + SourceChangeEvent, + TimeUpdateEvent, + VolumeChangeEvent, +} from 'theoplayer'; +import { AdScriptConfiguration } from './AdScriptConfiguration'; +import { EmbeddedContentMetadata, EmbeddedContentType, MainVideoContentMetadata, PlayerState } from './../adscript/AdScript' +import { Logger } from '../utils/Logger'; + +interface LogPoint { + offset: number; + name: string; + reported: boolean +} + +export class AdScriptTHEOIntegration { + // References for constructor arguments + private player: ChromelessPlayer; + private debug: boolean; + private adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; + private mainContentMetadata: MainVideoContentMetadata; + private mainContentLogPoints: LogPoint[] = []; + private mainContentDuration: number | undefined; + private currentAdMetadata: EmbeddedContentMetadata | undefined; + private currentAdLogPoints: LogPoint[] = [] + + private latestReportedEvent: string | undefined; + + private JHMTApi = window.JHMTApi; + private JHMT = window.JHMT; + + constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { + this.player = player; + this.debug = configuration.debug ?? false; + this.adProcessor = configuration?.adProcessor; + this.mainContentMetadata = metadata; + Logger.logSetContentMetadata(this.mainContentMetadata) + this.JHMTApi.setContentMetadata(this.mainContentMetadata) + this.reportPlayerState; + this.addListeners(); + } + + public updateMetadata(metadata: MainVideoContentMetadata) { + this.mainContentMetadata = metadata + Logger.logSetContentMetadata(this.mainContentMetadata) + this.JHMTApi.setContentMetadata(this.mainContentMetadata) + } + + public destroy() { + this.removeListeners(); + } + + private addListeners(): void { + this.player.addEventListener('durationchange', this.onDurationChange); + this.player.addEventListener('sourcechange', this.onSourceChange); + this.player.addEventListener('timeupdate', this.onTimeUpdate); + this.player.addEventListener('play', this.onPlay); // TODO + this.player.addEventListener('ended', this.onEnded); // TODO + this.player.addEventListener('volumechange', this.onVolumeChange); + this.player.addEventListener('ratechange', this.onRateChange); + this.player.addEventListener('presentationmodechange', this.onPresentationModeChange); + window.addEventListener("resize", this.reportPlayerState); + window.addEventListener("blur", this.reportPlayerState); + window.addEventListener("focus", this.reportPlayerState); + document.addEventListener("scroll", this.reportPlayerState); + document.addEventListener("visibilitychange", this.reportPlayerState); + if (this.player.ads) { + this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd); //TODO + this.player.ads.addEventListener('adbegin', this.onAdBegin); //TODO + this.player.ads.addEventListener("adfirstquartile", this.onAdFirstQuartile); + this.player.ads.addEventListener("admidpoint", this.onAdMidpoint); + this.player.ads.addEventListener("adthirdquartile", this.onAdTirdQuartile); + this.player.ads.addEventListener("adend", this.onAdEnd); + } + + } + + private removeListeners(): void { + this.player.removeEventListener('durationchange', this.onDurationChange); + this.player.removeEventListener('sourcechange', this.onSourceChange); + this.player.removeEventListener('timeupdate', this.onTimeUpdate); // TODO + this.player.removeEventListener('play', this.onPlay); // TODO + this.player.removeEventListener('ended', this.onEnded); // TODO + this.player.removeEventListener('volumechange', this.onVolumeChange); + this.player.removeEventListener('ratechange', this.onRateChange); + this.player.removeEventListener('presentationmodechange', this.onPresentationModeChange); + window.removeEventListener("resize", this.reportPlayerState); + window.removeEventListener("blur", this.reportPlayerState); + window.removeEventListener("focus", this.reportPlayerState); + document.removeEventListener("scroll", this.reportPlayerState); + document.removeEventListener("visibilitychange", this.reportPlayerState); + if (this.player.ads) { + this.player.ads.removeEventListener('adbreakend', this.onAdBreakEnd); //TODO + this.player.ads.removeEventListener('adbegin', this.onAdBegin); //TODO + } + this.player.removeEventListener('playing', this.onFirstMainContentPlaying) + } + + // EVENT HANDLERS + private onDurationChange = (event: DurationChangeEvent) => { + if (this.player.ads?.playing || this.mainContentLogPoints.length) return; + const { duration } = event; + this.mainContentDuration = duration + if (duration === Infinity) { + this.mainContentLogPoints = [{reported: false, offset: this.player.currentTime + 1, name: "progress1"}] + } else { + this.mainContentLogPoints = [ + {reported: false, offset: duration * 0.75, name: "thirdQuartile"}, + {reported: false, offset: duration * 0.5, name: "midpoint"}, + {reported: false, offset: duration * 0.25, name: "firstQuartile"}, + {reported: false, offset: 1, name: "progress1"} + ] + } + } + + private onSourceChange = (event: SourceChangeEvent) => { + Logger.logEvent(event); + this.player.addEventListener('playing', this.onFirstMainContentPlaying) + this.mainContentLogPoints = [] + this.currentAdLogPoints = [] + this.currentAdMetadata = undefined + }; + + private onTimeUpdate = (event: TimeUpdateEvent) => { + const { currentTime } = event; + if (this.currentAdMetadata) { + this.maybeReportLogPoint(currentTime, this.currentAdMetadata, this.currentAdLogPoints) + } else { + this.maybeReportLogPoint(currentTime, this.mainContentMetadata, this.mainContentLogPoints) + } + } + + private onFirstMainContentPlaying = () => { + if (this.player.ads?.playing) return; + Logger.logAdScriptEvent("start",this.mainContentMetadata); + this.JHMT.push(["start", this.mainContentMetadata]); + this.player.removeEventListener("playing", this.onFirstMainContentPlaying); + } + + private onPlay = (event: PlayEvent) => { + Logger.logEvent(event); + this.reportPlayerState; + } + + private onEnded = (event: EndedEvent) => { + Logger.logEvent(event); + Logger.logAdScriptEvent("complete",this.mainContentMetadata); + this.JHMT.push(["complete", this.mainContentMetadata]); + } + + private onVolumeChange = (event: VolumeChangeEvent) => { + Logger.logEvent(event); + this.reportPlayerState(); + } + + private onRateChange = (event: RateChangeEvent) => { + Logger.logEvent(event); + this.reportPlayerState(); + } + + private onPresentationModeChange = (event: Event) => { + Logger.logEvent(event); + this.reportPlayerState(); + } + + private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { + Logger.logEvent(event); + this.currentAdLogPoints = []; + this.currentAdMetadata = undefined; + } + + private onAdFirstQuartile = (event: AdEvent<'adfirstquartile'>) => { + Logger.logEvent(event); + Logger.logAdScriptEvent("firstquartile",this.currentAdMetadata); + this.JHMT.push(["firstquartile", this.currentAdMetadata]) + } + private onAdMidpoint = (event: AdEvent<'admidpoint'>) => { + Logger.logEvent(event); + Logger.logAdScriptEvent("midpoint",this.currentAdMetadata); + this.JHMT.push(["midpoint", this.currentAdMetadata]) + } + private onAdTirdQuartile = (event: AdEvent<'adthirdquartile'>) => { + Logger.logEvent(event); + Logger.logAdScriptEvent("thirdquartile",this.currentAdMetadata); + this.JHMT.push(["thirdquartile", this.currentAdMetadata]) + } + private onAdEnd = (event: AdEvent<'adend'>) => { + Logger.logEvent(event); + Logger.logAdScriptEvent("complete",this.currentAdMetadata); + this.JHMT.push(["complete", this.currentAdMetadata]) + } + + private onAdBegin = (event: AdEvent<'adbegin'>) => { + Logger.logEvent(event); + if (event.ad.type !== "linear") return + const adMetadataObject = this.buildAdMetadataObject(event) + this.currentAdMetadata = adMetadataObject + this.currentAdLogPoints = this.buildAdLogPoints(event.ad) + Logger.logAdScriptEvent("start",this.currentAdMetadata); + this.JHMT.push(["start",this.currentAdMetadata]) + } + + private buildAdLogPoints = (ad: Ad) => { + const { duration } = ad + if (ad.adBreak.integration === "theo" && duration) { + return [ + {reported: false, offset: duration * 0.75, name: "thirdQuartile"}, + {reported: false, offset: duration * 0.5, name: "midpoint"}, + {reported: false, offset: duration * 0.25, name: "firstQuartile"}, + {reported: false, offset: 1, name: "progress1"} + ] + } + return [{reported: false, offset: 1, name: "progress1"}] + } + + private buildAdMetadataObject = (event: AdEvent<'adbegin'>): EmbeddedContentMetadata => { + const { ad } = event; + const { adBreak } = ad; + if (this.adProcessor) { + return { + ...this.adProcessor(ad), + type: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), + length: ad.duration?.toString() ?? "" + } + } + return { + assetid: ad.id ?? "", + type: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), + length: ad.duration?.toString() ?? "", + title: ad.integration?.includes("google") ? (ad as GoogleImaAd).title ?? "" : "", + asmea: "", + attributes: "" + } + } + + private getAdType = (offset: number, duration: number, integration: string | undefined): EmbeddedContentType => { + if (offset === 0) return "preroll"; + if (offset === -1) return "postroll"; + if (duration - offset < 1 && integration === "google-dai") return "postroll" + if (this.mainContentDuration && this.mainContentDuration - offset < 1 ) return "postroll" + return "midroll" + } + + private reportPlayerState = () => { + const playerState: PlayerState = { + muted: this.player.muted ? 1 : 0, + volume: this.player.volume * 100, + triggeredByUser: this.player.autoplay ? 1 : 0, + normalSpeed: this.player.playbackRate === 1 ? 1 : 0, + fullscreen: this.player.presentation.currentMode === "fullscreen" ? 1 : 0, + visibility: this.player.visibility.ratio * 100, + width: this.player.element.clientWidth, + height: this.player.element.clientHeight + } + Logger.logPlayerState(playerState) + this.JHMTApi.setPlayerState(playerState) + } + + private maybeReportLogPoint = (currentTime: number, metadata: MainVideoContentMetadata | EmbeddedContentMetadata, logPoints: LogPoint[]) => { + logPoints.forEach(logPoint => { + const { reported, offset, name } = logPoint + if (!reported && currentTime >= offset && currentTime < offset + 1) { + logPoint.reported = true + Logger.logAdScriptEvent(name,metadata); + this.JHMT.push([name,metadata]) + } + }) + } +} diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts new file mode 100644 index 00000000..d3724a98 --- /dev/null +++ b/adscript/src/utils/Logger.ts @@ -0,0 +1,26 @@ +import { Event } from "theoplayer"; +import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from "../adscript/AdScript"; + +const LOG_THEOPLAYER_EVENTS = true; +const LOG_SETPLAYERSTATE = true +const LOG_SETMETADATA = true +const LOG_ADSCRIPT_EVENTS = true + +export class Logger { + static logEvent = (event: Event) => { + if (LOG_THEOPLAYER_EVENTS) + console.log(`[ADSCRIPT - THEOplayer EVENTS] ${event.type} event`); + } + + static logPlayerState = (playerState: PlayerState) => { + if (LOG_SETPLAYERSTATE) console.log(`[ADSCRIPT - setPlayerState]`,playerState); + } + + static logSetContentMetadata = (metadata: MainVideoContentMetadata) => { + if (LOG_SETMETADATA) console.log(`[ADSCRIPT - setContentMetadata]`,metadata); + } + + static logAdScriptEvent = (name: string, metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined) => { + if (LOG_ADSCRIPT_EVENTS) console.log(`[ADSCRIPT - EVENT] ${name}`,metadata) + } +} \ No newline at end of file From 6bf9dfbea06e93b2b29e611a07675f4a79e8e981 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:31:15 +0200 Subject: [PATCH 03/59] empty changelog --- adscript/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 adscript/CHANGELOG.md diff --git a/adscript/CHANGELOG.md b/adscript/CHANGELOG.md new file mode 100644 index 00000000..2ce1eace --- /dev/null +++ b/adscript/CHANGELOG.md @@ -0,0 +1,7 @@ +# @theoplayer/adscript-connector-web + +## 0.0.1 + +### ✨ Features + +- Initial release. From cd30b20f6d5f9323e65948ab178312d847b5d335 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:31:29 +0200 Subject: [PATCH 04/59] basic README --- adscript/README.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 adscript/README.md diff --git a/adscript/README.md b/adscript/README.md new file mode 100644 index 00000000..c277dffd --- /dev/null +++ b/adscript/README.md @@ -0,0 +1,72 @@ +# adscript-connector-web + +The AdScript connector provides a AdScript integration for THEOplayer. + +## Installation + +```sh +npm install @theoplayer/adscript-connector-web +``` + +Initialize AdScript Measurement by including this script in your app's html. + +```html + +``` + +## Usage + +### Configuring the connector + +```js +import { AdScriptConnector } from '../../dist/adscript-connector.esm.js'; +// TODO +``` + +## Documentation + +Documentation can be acquired through the [AdScript documentation website](https://adscript.admosphere.cz/). From 54169c9b68c57ee72e527b13fda0e6c828b45420 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:32:01 +0200 Subject: [PATCH 05/59] config --- adscript/.gitignore | 10 ++++++++++ adscript/package-lock.json | 22 +++++++++++++++++++++ adscript/package.json | 40 ++++++++++++++++++++++++++++++++++++++ adscript/rollup.config.mjs | 15 ++++++++++++++ adscript/tsconfig.json | 11 +++++++++++ adscript/typedoc.json | 12 ++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 adscript/.gitignore create mode 100644 adscript/package-lock.json create mode 100644 adscript/package.json create mode 100644 adscript/rollup.config.mjs create mode 100644 adscript/tsconfig.json create mode 100644 adscript/typedoc.json diff --git a/adscript/.gitignore b/adscript/.gitignore new file mode 100644 index 00000000..92b3d00f --- /dev/null +++ b/adscript/.gitignore @@ -0,0 +1,10 @@ +# Node artifact files +node_modules/ +lib/ +dist/ + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db diff --git a/adscript/package-lock.json b/adscript/package-lock.json new file mode 100644 index 00000000..a9e37563 --- /dev/null +++ b/adscript/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "@theoplayer/adscript-connector-web", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@theoplayer/adscript-connector-web", + "version": "0.0.1", + "license": "MIT", + "peerDependencies": { + "theoplayer": "^7.0.0" + } + }, + "node_modules/theoplayer": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-7.7.1.tgz", + "integrity": "sha512-876lU51HWPO7qvCU8bZDyC/WW9UsezQu6JKJWPWrPT2BsHVY6ESl2GFT044v7iGRNxsU9neO+uUo4JJtAT1NYQ==", + "peer": true + } + } +} diff --git a/adscript/package.json b/adscript/package.json new file mode 100644 index 00000000..d58040d6 --- /dev/null +++ b/adscript/package.json @@ -0,0 +1,40 @@ +{ + "name": "@theoplayer/adscript-connector-web", + "version": "0.0.1", + "description": "A connector implementing AdScript with THEOplayer", + "main": "dist/adscript-connector.umd.js", + "module": "dist/adscript-connector.esm.js", + "types": "dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/adscript-connector.esm.js", + "require": "./dist/adscript-connector.umd.js" + }, + "./dist/*": "./dist/*", + "./package": "./package.json", + "./package.json": "./package.json" + }, + "scripts": { + "clean": "rimraf lib dist", + "bundle": "rollup -c rollup.config.mjs", + "watch": "npm run bundle -- --watch", + "build": "npm run clean && npm run bundle", + "serve": "http-server ./.. -o /adscript/test/pages/main_esm.html", + "test": "echo \"No tests yet\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/THEOplayer/web-connectors.git", + "directory": "adscript" + }, + "author": "THEO Technologies NV", + "license": "MIT", + "bugs": { + "url": "https://github.com/THEOplayer/web-connectors/issues" + }, + "homepage": "https://github.com/THEOplayer/web-connectors/tree/main/adscript#readme", + "peerDependencies": { + "theoplayer": "^7.0.0" + } +} diff --git a/adscript/rollup.config.mjs b/adscript/rollup.config.mjs new file mode 100644 index 00000000..49f0009a --- /dev/null +++ b/adscript/rollup.config.mjs @@ -0,0 +1,15 @@ +import fs from "node:fs"; +import {getSharedBuildConfiguration} from "../tools/build.mjs"; + + +const {version} = JSON.parse(fs.readFileSync("./package.json", "utf8")); + +const fileName = "adscript-connector"; +const globalName = "THEOplayerAdScriptConnector"; + +const banner = ` +/** + * THEOplayer AdScript Web Connector v${version} + */`.trim(); + +export default getSharedBuildConfiguration({fileName, globalName, banner}); diff --git a/adscript/tsconfig.json b/adscript/tsconfig.json new file mode 100644 index 00000000..c9804acc --- /dev/null +++ b/adscript/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declarationDir": "dist/types" + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file diff --git a/adscript/typedoc.json b/adscript/typedoc.json new file mode 100644 index 00000000..0d320987 --- /dev/null +++ b/adscript/typedoc.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "extends": [ + "../typedoc.base.json" + ], + "entryPoints": [ + "src/index.ts" + ], + "tsconfig": "tsconfig.json", + "readme": "README.md", + "name": "AdScript Connector" +} From 90547a44c8d2265fbfcc8ad6f10d5cdd9cde4293 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:32:12 +0200 Subject: [PATCH 06/59] add test assets --- adscript/test/pages/test-assets.json | 225 +++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 adscript/test/pages/test-assets.json diff --git a/adscript/test/pages/test-assets.json b/adscript/test/pages/test-assets.json new file mode 100644 index 00000000..4519f750 --- /dev/null +++ b/adscript/test/pages/test-assets.json @@ -0,0 +1,225 @@ +[ + { + "label": "Integration Guide Example", + "source": { + "sources": [ + { + "src": "https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd", + "useCredentials": false + } + ], + "ads": [ + { + "integration": "google-ima", + "timeOffset": "start", + "sources": "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" + } + ] + }, + "metadata": { + "assetid": "v0000001", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video - Extended", + "length": "635", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + } + }, + { + "label": "VOD (HLS)", + "source": { + "sources": [ + { + "src": "https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8", + "type": "application/x-mpegurl" + } + ] + }, + "metadata": { + "assetid": "v0000002", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video", + "length": "596", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + } + }, + { + "label": "VOD (HLS) - VMAP (IMA)", + "source": { + "sources": [ + { + "src": "https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8", + "type": "application/x-mpegurl" + } + ], + "ads": [ + { + "integration": "google-ima", + "sources": "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostpod&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=" + } + ] + }, + "metadata": { + "assetid": "v0000002", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video", + "length": "596", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + } + }, + { + "label": "VOD (HLS) - VMAP (THEOAds)", + "source": { + "sources": [ + { + "src": "https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8", + "type": "application/x-mpegurl" + } + ], + "ads": [ + { + "integration": "theo", + "sources": "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostpod&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=" + } + ] + }, + "metadata": { + "assetid": "v0000002", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video", + "length": "596", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + } + }, + { + "label": "LIVE (DASH) - VAST pre-roll (IMA)", + "source": { + "sources": [ + { + "src": "https://livesim2.dashif.org/livesim2/testpic_2s/Manifest.mpd", + "useCredentials": false + } + ], + "ads": [ + { + "integration": "google-ima", + "timeOffset": "start", + "sources": "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" + } + ] + }, + "metadata": { + "assetid": "v0000003", + "type": "content", + "program": "DASHIF Test Assets", + "title": "Livesim", + "length": "86400", + "crossId": "000 111 333333", + "livestream": "1", + "channelId": "DASHIF1", + "attribute": "1" + } + }, + { + "label": "LIVE (DASH) - empty VAST pre-roll (IMA)", + "source": { + "sources": [ + { + "src": "https://livesim2.dashif.org/livesim2/testpic_2s/Manifest.mpd", + "useCredentials": false + } + ], + "ads": [ + { + "integration": "google-ima", + "timeOffset": "start", + "sources": "http://localhost:8081/adscript/test/pages/preroll-empty.xml" + } + ] + }, + "metadata": { + "assetid": "v0000003", + "type": "content", + "program": "DASHIF Test Assets", + "title": "Livesim", + "length": "86400", + "crossId": "000 111 333333", + "livestream": "1", + "channelId": "DASHIF1", + "attribute": "1" + } + }, + { + "label": "LIVE (DASH) - VAST pre-roll (THEOAds)", + "source": { + "sources": [ + { + "src": "https://livesim2.dashif.org/livesim2/testpic_2s/Manifest.mpd", + "useCredentials": false + } + ], + "ads": [ + { + "integration": "theo", + "timeOffset": "start", + "sources": "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" + } + ] + }, + "metadata": { + "assetid": "v0000003", + "type": "content", + "program": "DASHIF Test Assets", + "title": "Livesim", + "length": "86400", + "crossId": "000 111 333333", + "livestream": "1", + "channelId": "DASHIF1", + "attribute": "1" + } + }, + { + "label": "VOD - Google DAI", + "source": { + "sources": [ + { + "type": "application/x-mpegurl", + "ssai": { + "integration": "google-dai", + "availabilityType": "vod", + "contentSourceID": "2548831", + "videoID": "tears-of-steel", + "assetKey": "", + "apiKey": "" + } + } + ] + }, + "metadata": { + "assetid": "v0000004", + "type": "content", + "program": "DAI VOD Samples", + "title": "Tears Of Steel", + "length": "784", + "crossId": "000 111 333333", + "livestream": "0", + "channelId": "", + "attribute": "1" + } + } +] \ No newline at end of file From 6d4e852d939df68f9337676b92239d8f3265e5ac Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:32:27 +0200 Subject: [PATCH 07/59] add empty VAST for testing purposes --- adscript/test/pages/preroll-empty.xml | 1 + 1 file changed, 1 insertion(+) create mode 100644 adscript/test/pages/preroll-empty.xml diff --git a/adscript/test/pages/preroll-empty.xml b/adscript/test/pages/preroll-empty.xml new file mode 100644 index 00000000..6850c951 --- /dev/null +++ b/adscript/test/pages/preroll-empty.xml @@ -0,0 +1 @@ + \ No newline at end of file From a21925885fcd5db9de01879cff957a883d3a1f1e Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 00:35:11 +0200 Subject: [PATCH 08/59] add test pages --- adscript/test/pages/main_esm.html | 148 ++++++++++++++++++++++++++++++ adscript/test/pages/main_umd.html | 139 ++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 adscript/test/pages/main_esm.html create mode 100644 adscript/test/pages/main_umd.html diff --git a/adscript/test/pages/main_esm.html b/adscript/test/pages/main_esm.html new file mode 100644 index 00000000..f33a2a0f --- /dev/null +++ b/adscript/test/pages/main_esm.html @@ -0,0 +1,148 @@ + + + + + Connector test page + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ + + + + + + diff --git a/adscript/test/pages/main_umd.html b/adscript/test/pages/main_umd.html new file mode 100644 index 00000000..c3ba2e54 --- /dev/null +++ b/adscript/test/pages/main_umd.html @@ -0,0 +1,139 @@ + + + + + Connector test page + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ + + + + + From 2ac977ba4ae02407be016929cd68354e7a479cc2 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:10:17 +0200 Subject: [PATCH 09/59] rename test asset --- adscript/test/pages/test-assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/test/pages/test-assets.json b/adscript/test/pages/test-assets.json index 4519f750..8dcf0ba5 100644 --- a/adscript/test/pages/test-assets.json +++ b/adscript/test/pages/test-assets.json @@ -1,6 +1,6 @@ [ { - "label": "Integration Guide Example", + "label": "VOD (DASH) - VAST (IMA)", "source": { "sources": [ { From 0bb8cde72b352fcd177fe5075957f3ded9dbff63 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:10:36 +0200 Subject: [PATCH 10/59] fix double start event for main content --- adscript/src/integration/AdScriptTHEOIntegration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 35876c59..1e9c8e69 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -125,6 +125,7 @@ export class AdScriptTHEOIntegration { private onSourceChange = (event: SourceChangeEvent) => { Logger.logEvent(event); + this.player.removeEventListener('playing', this.onFirstMainContentPlaying) this.player.addEventListener('playing', this.onFirstMainContentPlaying) this.mainContentLogPoints = [] this.currentAdLogPoints = [] From 6caff9399f1d9414b90b268c9b478fdf5e7eed3c Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:30:51 +0200 Subject: [PATCH 11/59] fix start and progress1 reporting for google dai --- adscript/src/integration/AdScriptTHEOIntegration.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 1e9c8e69..d6425488 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -110,6 +110,8 @@ export class AdScriptTHEOIntegration { private onDurationChange = (event: DurationChangeEvent) => { if (this.player.ads?.playing || this.mainContentLogPoints.length) return; const { duration } = event; + const firstSecondOfMainContent = this.player.ads?.dai?.streamTimeForContentTime(1); + const useDAITimeline = firstSecondOfMainContent && firstSecondOfMainContent !== 1; this.mainContentDuration = duration if (duration === Infinity) { this.mainContentLogPoints = [{reported: false, offset: this.player.currentTime + 1, name: "progress1"}] @@ -118,7 +120,7 @@ export class AdScriptTHEOIntegration { {reported: false, offset: duration * 0.75, name: "thirdQuartile"}, {reported: false, offset: duration * 0.5, name: "midpoint"}, {reported: false, offset: duration * 0.25, name: "firstQuartile"}, - {reported: false, offset: 1, name: "progress1"} + {reported: false, offset: useDAITimeline ? firstSecondOfMainContent : 1, name: "progress1"} ] } } @@ -142,7 +144,8 @@ export class AdScriptTHEOIntegration { } private onFirstMainContentPlaying = () => { - if (this.player.ads?.playing) return; + const isBeforePreroll = this.player.ads?.scheduledAdBreaks.find(adBreak => adBreak.timeOffset === 0); + if (this.player.ads?.playing || isBeforePreroll) return; Logger.logAdScriptEvent("start",this.mainContentMetadata); this.JHMT.push(["start", this.mainContentMetadata]); this.player.removeEventListener("playing", this.onFirstMainContentPlaying); @@ -176,8 +179,13 @@ export class AdScriptTHEOIntegration { private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { Logger.logEvent(event); + const { adBreak } = event; + const { timeOffset, integration } = adBreak this.currentAdLogPoints = []; this.currentAdMetadata = undefined; + if (integration === "google-dai" && timeOffset === 0) { + this.onFirstMainContentPlaying() + } } private onAdFirstQuartile = (event: AdEvent<'adfirstquartile'>) => { From 64e947778b472e1b7193119e7baa7052dabf4e2c Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:44:07 +0200 Subject: [PATCH 12/59] poll for presence of JHMTApi --- adscript/src/integration/AdScriptConnector.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 78c72085..a035a0ab 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -14,11 +14,20 @@ export class AdScriptConnector { * @returns */ constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { - if (!window.JHMTApi || !window.JHMT) { - console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement') - return; - } - this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata) + const interval = window.setInterval(() => { + if (typeof window.JHMTApi === 'object') { + window.clearInterval(interval); + this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata) + + } + }, 20) + window.setTimeout(() => { + if (!window.JHMTApi) { + window.clearInterval(interval) + console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement') + return; + } + }, 5000) } updateMetadata(metadata: any): void { From 3eb0ecba96d554ec6051b678f2c6161e2244a540 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:44:33 +0200 Subject: [PATCH 13/59] invoke reportPlayerState in constructor --- adscript/src/integration/AdScriptTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index d6425488..e620c313 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -46,7 +46,7 @@ export class AdScriptTHEOIntegration { this.mainContentMetadata = metadata; Logger.logSetContentMetadata(this.mainContentMetadata) this.JHMTApi.setContentMetadata(this.mainContentMetadata) - this.reportPlayerState; + this.reportPlayerState(); this.addListeners(); } From 353dd9e42d0302c0fa3b4c9e9f95be3f49b80d6e Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 22:46:58 +0200 Subject: [PATCH 14/59] add first playing listener when connector is initialized --- adscript/src/integration/AdScriptTHEOIntegration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index e620c313..2d5fdf0b 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -61,6 +61,7 @@ export class AdScriptTHEOIntegration { } private addListeners(): void { + this.player.addEventListener('playing', this.onFirstMainContentPlaying) this.player.addEventListener('durationchange', this.onDurationChange); this.player.addEventListener('sourcechange', this.onSourceChange); this.player.addEventListener('timeupdate', this.onTimeUpdate); From ef9781a5f267ed3c90e7c119211759a21ef6b0e5 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 15 Jul 2024 23:14:20 +0200 Subject: [PATCH 15/59] add i12n reporting --- adscript/src/integration/AdScriptConfiguration.ts | 1 + adscript/src/integration/AdScriptConnector.ts | 6 ++++++ adscript/src/utils/Logger.ts | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 87fbe31e..752b0b94 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -3,6 +3,7 @@ import { EmbeddedContentMetadata } from "../adscript/AdScript"; export interface AdScriptConfiguration { implementationId: string; + i12n: {[key: string]: string} debug?: boolean; adProcessor?: (ad: Ad) => EmbeddedContentMetadata } \ No newline at end of file diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index a035a0ab..4ca01e64 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -2,6 +2,7 @@ import { ChromelessPlayer } from 'theoplayer'; import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; import { AdScriptConfiguration } from './AdScriptConfiguration'; import { MainVideoContentMetadata } from '../adscript/AdScript'; +import { Logger } from '../utils/Logger'; export class AdScriptConnector { @@ -17,6 +18,11 @@ export class AdScriptConnector { const interval = window.setInterval(() => { if (typeof window.JHMTApi === 'object') { window.clearInterval(interval); + const { i12n } = configuration + for (const id in i12n) { + window.JHMTApi.setI12n(id, i12n[id]) + Logger.logsetI12n(id, i12n[id]); + } this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata) } diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index d3724a98..3a53dfd4 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -5,6 +5,7 @@ const LOG_THEOPLAYER_EVENTS = true; const LOG_SETPLAYERSTATE = true const LOG_SETMETADATA = true const LOG_ADSCRIPT_EVENTS = true +const LOG_SETI12N = true; export class Logger { static logEvent = (event: Event) => { @@ -23,4 +24,8 @@ export class Logger { static logAdScriptEvent = (name: string, metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined) => { if (LOG_ADSCRIPT_EVENTS) console.log(`[ADSCRIPT - EVENT] ${name}`,metadata) } + + static logsetI12n = (id: string, value: string) => { + if (LOG_SETI12N) console.log(`[ADSCRIPT - SET I12N] ${id}: ${value}`) + } } \ No newline at end of file From 2b82900b5e33b4f11559c1b2bce85a8e80c12842 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 11:32:21 +0200 Subject: [PATCH 16/59] Add Adscript to workspace --- adscript/package-lock.json | 22 ---------------------- adscript/package.json | 7 +++++++ package-lock.json | 16 ++++++++++++++-- package.json | 3 ++- 4 files changed, 23 insertions(+), 25 deletions(-) delete mode 100644 adscript/package-lock.json diff --git a/adscript/package-lock.json b/adscript/package-lock.json deleted file mode 100644 index a9e37563..00000000 --- a/adscript/package-lock.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@theoplayer/adscript-connector-web", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@theoplayer/adscript-connector-web", - "version": "0.0.1", - "license": "MIT", - "peerDependencies": { - "theoplayer": "^7.0.0" - } - }, - "node_modules/theoplayer": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-7.7.1.tgz", - "integrity": "sha512-876lU51HWPO7qvCU8bZDyC/WW9UsezQu6JKJWPWrPT2BsHVY6ESl2GFT044v7iGRNxsU9neO+uUo4JJtAT1NYQ==", - "peer": true - } - } -} diff --git a/adscript/package.json b/adscript/package.json index d58040d6..ef07ea4c 100644 --- a/adscript/package.json +++ b/adscript/package.json @@ -34,6 +34,13 @@ "url": "https://github.com/THEOplayer/web-connectors/issues" }, "homepage": "https://github.com/THEOplayer/web-connectors/tree/main/adscript#readme", + "files": [ + "dist/", + "CHANGELOG.md", + "README.md", + "LICENSE.md", + "package.json" + ], "peerDependencies": { "theoplayer": "^7.0.0" } diff --git a/package-lock.json b/package-lock.json index cf4c2c6c..e36ef6f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "conviva", "nielsen", "cmcd", - "comscore" + "comscore", + "adscript" ], "devDependencies": { "@changesets/cli": "^2.27.1", @@ -42,6 +43,13 @@ "typescript-eslint": "^7.5.0" } }, + "adscript": { + "version": "0.0.1", + "license": "MIT", + "peerDependencies": { + "theoplayer": "^7.0.0" + } + }, "cmcd": { "name": "@theoplayer/cmcd-connector-web", "version": "1.0.2", @@ -2396,6 +2404,10 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@theoplayer/adscript-connector-web": { + "resolved": "adscript", + "link": true + }, "node_modules/@theoplayer/cmcd-connector-web": { "resolved": "cmcd", "link": true @@ -8737,7 +8749,7 @@ }, "yospace": { "name": "@theoplayer/yospace-connector-web", - "version": "2.1.3", + "version": "2.2.0", "license": "MIT", "peerDependencies": { "theoplayer": "^5.0.0 || ^6.0.0 || ^7.0.0" diff --git a/package.json b/package.json index 14a91e11..b56f2b8f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "conviva", "nielsen", "cmcd", - "comscore" + "comscore", + "adscript" ], "scripts": { "changeset:version": "changeset version && node .changeset/post-process.js", From 9d6015021e1345c98725eb81c3bd7b5d5204d583 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 11:34:29 +0200 Subject: [PATCH 17/59] Use changeset for initial release --- .changeset/ten-zoos-sing.md | 5 +++++ adscript/CHANGELOG.md | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 .changeset/ten-zoos-sing.md delete mode 100644 adscript/CHANGELOG.md diff --git a/.changeset/ten-zoos-sing.md b/.changeset/ten-zoos-sing.md new file mode 100644 index 00000000..c05c0c19 --- /dev/null +++ b/.changeset/ten-zoos-sing.md @@ -0,0 +1,5 @@ +--- +"@theoplayer/adscript-connector-web": minor +--- + +Initial release. diff --git a/adscript/CHANGELOG.md b/adscript/CHANGELOG.md deleted file mode 100644 index 2ce1eace..00000000 --- a/adscript/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# @theoplayer/adscript-connector-web - -## 0.0.1 - -### ✨ Features - -- Initial release. From 8a1d43685590ebd76701116566679ea912bb1e12 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 11:47:46 +0200 Subject: [PATCH 18/59] Add exclude --- .idea/web-connectors.iml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/web-connectors.iml b/.idea/web-connectors.iml index 447c428e..c2d8285e 100644 --- a/.idea/web-connectors.iml +++ b/.idea/web-connectors.iml @@ -10,6 +10,7 @@ + From 3882911e8eb8a3522f1121427e44faf31806eb39 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 11:47:56 +0200 Subject: [PATCH 19/59] Fixup package-lock --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index e36ef6f7..8c492a18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ } }, "adscript": { + "name": "@theoplayer/adscript-connector-web", "version": "0.0.1", "license": "MIT", "peerDependencies": { From e61ec1610c3e4b1df05eaff237d519bb6f3ada35 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 12:02:51 +0200 Subject: [PATCH 20/59] Refer to official documentation instead --- adscript/README.md | 47 +++------------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/adscript/README.md b/adscript/README.md index c277dffd..bcde7966 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -8,53 +8,12 @@ The AdScript connector provides a AdScript integration for THEOplayer. npm install @theoplayer/adscript-connector-web ``` -Initialize AdScript Measurement by including this script in your app's html. +First you need to initialize the AdScript Measurement by including the script in your app's html. ```html ``` From 576d61028cc86b565cdacfed1f726adb8c7aa9dc Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 12:03:08 +0200 Subject: [PATCH 21/59] Remove comment --- adscript/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/adscript/src/index.ts b/adscript/src/index.ts index ec58a5f5..c904706c 100644 --- a/adscript/src/index.ts +++ b/adscript/src/index.ts @@ -1,3 +1,2 @@ export { AdScriptConnector } from './integration/AdScriptConnector'; export * from './integration/AdScriptConfiguration' -// export * from './api/path/to/typing/helpers/etc'; From 8878da58f54a79e08350b72ad2539731aa2c8ecf Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 12:03:24 +0200 Subject: [PATCH 22/59] Add param to JSdocs --- adscript/src/integration/AdScriptConnector.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 4ca01e64..9b234860 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -12,7 +12,8 @@ export class AdScriptConnector { * Constructor for the THEOplayer AdScript connector * @param player a THEOplayer instance reference * @param configuration a configuration object for the AdScript connector - * @returns + * @param metadata the MainVideoContentMetadata + * @returns */ constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { const interval = window.setInterval(() => { From 99bea78723973e6325739608a9b2541c500cc588 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 12:05:19 +0200 Subject: [PATCH 23/59] Run prettier --- adscript/src/adscript/AdScript.d.ts | 99 ++++--- adscript/src/index.ts | 2 +- .../src/integration/AdScriptConfiguration.ts | 10 +- adscript/src/integration/AdScriptConnector.ts | 37 ++- .../integration/AdScriptTHEOIntegration.ts | 246 +++++++++--------- adscript/src/utils/Logger.ts | 38 +-- 6 files changed, 220 insertions(+), 212 deletions(-) diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts index 59b42148..14fb9817 100644 --- a/adscript/src/adscript/AdScript.d.ts +++ b/adscript/src/adscript/AdScript.d.ts @@ -1,76 +1,75 @@ -export type JHMTApiProtocol = "https:" | "http:" | "file:" +export type JHMTApiProtocol = 'https:' | 'http:' | 'file:'; interface I12n { - i1: string; - i2: string; - i3: string; - i4: string; - i5: string; + i1: string; + i2: string; + i3: string; + i4: string; + i5: string; } -export type MainVideoContentType = "content" -export type EmbeddedContentType = "preroll" | "midroll" | "postroll" -export type StaticContentType = "static" +export type MainVideoContentType = 'content'; +export type EmbeddedContentType = 'preroll' | 'midroll' | 'postroll'; +export type StaticContentType = 'static'; export interface MainVideoContentMetadata { - assetid: string; - type: MainVideoContentType; - program: string; - title: string; - length: string; - crossId: string; - livestream: string; - channelId: string; - attributes: string; + assetid: string; + type: MainVideoContentType; + program: string; + title: string; + length: string; + crossId: string; + livestream: string; + channelId: string; + attributes: string; } interface EmbeddedContentMetadata { - assetid: string; - type: EmbeddedContentType; - length: string; - title: string; - asmea: string; - attributes: string; + assetid: string; + type: EmbeddedContentType; + length: string; + title: string; + asmea: string; + attributes: string; } - interface StaticContentMetadata { - assetid: string; - type: MainVideoContentType; - sec1: string; - sec2: string; - sec3: string; - sec4: string; - ref: string; + assetid: string; + type: MainVideoContentType; + sec1: string; + sec2: string; + sec3: string; + sec4: string; + ref: string; } export interface PlayerState { - muted: number; - volume: number; - triggeredByUser: number; - normalSpeed: number; - fullscreen: number; - visibility: number; - width: number; - height: number; + muted: number; + volume: number; + triggeredByUser: number; + normalSpeed: number; + fullscreen: number; + visibility: number; + width: number; + height: number; } interface JHMTArray extends Array { - i12n: I12n; - contentMetadata: ContentMetadata; - playerState: PlayerState; - push: (item: any) => number; // Type of the push function + i12n: I12n; + contentMetadata: ContentMetadata; + playerState: PlayerState; + push: (item: any) => number; // Type of the push function } declare global { - interface Window { - JHMT: JHMTArray; - JHMTApi: typeof JHMTApi; - JHMTApiProtocol: JHMTApiProtocol - } + interface Window { + JHMT: JHMTArray; + JHMTApi: typeof JHMTApi; + JHMTApiProtocol: JHMTApiProtocol; + } } export interface JHMTApi { setI12n(i12n: I12n); setContentMetadata(contentMetadata: ContentMetadata); setPlayerState(playerState: PlayerState); -} \ No newline at end of file +} diff --git a/adscript/src/index.ts b/adscript/src/index.ts index c904706c..da9e700c 100644 --- a/adscript/src/index.ts +++ b/adscript/src/index.ts @@ -1,2 +1,2 @@ export { AdScriptConnector } from './integration/AdScriptConnector'; -export * from './integration/AdScriptConfiguration' +export * from './integration/AdScriptConfiguration'; diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 752b0b94..8121056a 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -1,9 +1,9 @@ -import { Ad } from "theoplayer"; -import { EmbeddedContentMetadata } from "../adscript/AdScript"; +import { Ad } from 'theoplayer'; +import { EmbeddedContentMetadata } from '../adscript/AdScript'; export interface AdScriptConfiguration { implementationId: string; - i12n: {[key: string]: string} + i12n: { [key: string]: string }; debug?: boolean; - adProcessor?: (ad: Ad) => EmbeddedContentMetadata -} \ No newline at end of file + adProcessor?: (ad: Ad) => EmbeddedContentMetadata; +} diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 9b234860..11c3619b 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -5,7 +5,6 @@ import { MainVideoContentMetadata } from '../adscript/AdScript'; import { Logger } from '../utils/Logger'; export class AdScriptConnector { - private adscriptIntegration: AdScriptTHEOIntegration | undefined; /** @@ -15,37 +14,37 @@ export class AdScriptConnector { * @param metadata the MainVideoContentMetadata * @returns */ - constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { - const interval = window.setInterval(() => { - if (typeof window.JHMTApi === 'object') { - window.clearInterval(interval); - const { i12n } = configuration + constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { + const interval = window.setInterval(() => { + if (typeof window.JHMTApi === 'object') { + window.clearInterval(interval); + const { i12n } = configuration; for (const id in i12n) { - window.JHMTApi.setI12n(id, i12n[id]) + window.JHMTApi.setI12n(id, i12n[id]); Logger.logsetI12n(id, i12n[id]); } - this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata) - - } - }, 20) + this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata); + } + }, 20); window.setTimeout(() => { if (!window.JHMTApi) { - window.clearInterval(interval) - console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement') + window.clearInterval(interval); + console.error( + 'JHMT API not found, make sure you included the script to initialize AdScript Measurement' + ); return; } - }, 5000) + }, 5000); } updateMetadata(metadata: any): void { - this.adscriptIntegration?.updateMetadata(metadata) + this.adscriptIntegration?.updateMetadata(metadata); } - /** - * Destroy + * Destroy */ destroy(): void { - this.adscriptIntegration?.destroy() + this.adscriptIntegration?.destroy(); } -} \ No newline at end of file +} diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 2d5fdf0b..018d1932 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -1,4 +1,4 @@ -import { +import type { Ad, AdBreakEvent, AdEvent, @@ -11,16 +11,21 @@ import { RateChangeEvent, SourceChangeEvent, TimeUpdateEvent, - VolumeChangeEvent, + VolumeChangeEvent } from 'theoplayer'; import { AdScriptConfiguration } from './AdScriptConfiguration'; -import { EmbeddedContentMetadata, EmbeddedContentType, MainVideoContentMetadata, PlayerState } from './../adscript/AdScript' +import { + EmbeddedContentMetadata, + EmbeddedContentType, + MainVideoContentMetadata, + PlayerState +} from './../adscript/AdScript'; import { Logger } from '../utils/Logger'; interface LogPoint { offset: number; name: string; - reported: boolean + reported: boolean; } export class AdScriptTHEOIntegration { @@ -32,7 +37,7 @@ export class AdScriptTHEOIntegration { private mainContentLogPoints: LogPoint[] = []; private mainContentDuration: number | undefined; private currentAdMetadata: EmbeddedContentMetadata | undefined; - private currentAdLogPoints: LogPoint[] = [] + private currentAdLogPoints: LogPoint[] = []; private latestReportedEvent: string | undefined; @@ -41,19 +46,19 @@ export class AdScriptTHEOIntegration { constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { this.player = player; - this.debug = configuration.debug ?? false; + this.debug = configuration.debug ?? false; this.adProcessor = configuration?.adProcessor; this.mainContentMetadata = metadata; - Logger.logSetContentMetadata(this.mainContentMetadata) - this.JHMTApi.setContentMetadata(this.mainContentMetadata) + Logger.logSetContentMetadata(this.mainContentMetadata); + this.JHMTApi.setContentMetadata(this.mainContentMetadata); this.reportPlayerState(); this.addListeners(); } public updateMetadata(metadata: MainVideoContentMetadata) { - this.mainContentMetadata = metadata - Logger.logSetContentMetadata(this.mainContentMetadata) - this.JHMTApi.setContentMetadata(this.mainContentMetadata) + this.mainContentMetadata = metadata; + Logger.logSetContentMetadata(this.mainContentMetadata); + this.JHMTApi.setContentMetadata(this.mainContentMetadata); } public destroy() { @@ -61,29 +66,28 @@ export class AdScriptTHEOIntegration { } private addListeners(): void { - this.player.addEventListener('playing', this.onFirstMainContentPlaying) + this.player.addEventListener('playing', this.onFirstMainContentPlaying); this.player.addEventListener('durationchange', this.onDurationChange); this.player.addEventListener('sourcechange', this.onSourceChange); - this.player.addEventListener('timeupdate', this.onTimeUpdate); + this.player.addEventListener('timeupdate', this.onTimeUpdate); this.player.addEventListener('play', this.onPlay); // TODO this.player.addEventListener('ended', this.onEnded); // TODO this.player.addEventListener('volumechange', this.onVolumeChange); this.player.addEventListener('ratechange', this.onRateChange); this.player.addEventListener('presentationmodechange', this.onPresentationModeChange); - window.addEventListener("resize", this.reportPlayerState); - window.addEventListener("blur", this.reportPlayerState); - window.addEventListener("focus", this.reportPlayerState); - document.addEventListener("scroll", this.reportPlayerState); - document.addEventListener("visibilitychange", this.reportPlayerState); + window.addEventListener('resize', this.reportPlayerState); + window.addEventListener('blur', this.reportPlayerState); + window.addEventListener('focus', this.reportPlayerState); + document.addEventListener('scroll', this.reportPlayerState); + document.addEventListener('visibilitychange', this.reportPlayerState); if (this.player.ads) { this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd); //TODO this.player.ads.addEventListener('adbegin', this.onAdBegin); //TODO - this.player.ads.addEventListener("adfirstquartile", this.onAdFirstQuartile); - this.player.ads.addEventListener("admidpoint", this.onAdMidpoint); - this.player.ads.addEventListener("adthirdquartile", this.onAdTirdQuartile); - this.player.ads.addEventListener("adend", this.onAdEnd); + this.player.ads.addEventListener('adfirstquartile', this.onAdFirstQuartile); + this.player.ads.addEventListener('admidpoint', this.onAdMidpoint); + this.player.ads.addEventListener('adthirdquartile', this.onAdTirdQuartile); + this.player.ads.addEventListener('adend', this.onAdEnd); } - } private removeListeners(): void { @@ -95,16 +99,16 @@ export class AdScriptTHEOIntegration { this.player.removeEventListener('volumechange', this.onVolumeChange); this.player.removeEventListener('ratechange', this.onRateChange); this.player.removeEventListener('presentationmodechange', this.onPresentationModeChange); - window.removeEventListener("resize", this.reportPlayerState); - window.removeEventListener("blur", this.reportPlayerState); - window.removeEventListener("focus", this.reportPlayerState); - document.removeEventListener("scroll", this.reportPlayerState); - document.removeEventListener("visibilitychange", this.reportPlayerState); + window.removeEventListener('resize', this.reportPlayerState); + window.removeEventListener('blur', this.reportPlayerState); + window.removeEventListener('focus', this.reportPlayerState); + document.removeEventListener('scroll', this.reportPlayerState); + document.removeEventListener('visibilitychange', this.reportPlayerState); if (this.player.ads) { this.player.ads.removeEventListener('adbreakend', this.onAdBreakEnd); //TODO this.player.ads.removeEventListener('adbegin', this.onAdBegin); //TODO } - this.player.removeEventListener('playing', this.onFirstMainContentPlaying) + this.player.removeEventListener('playing', this.onFirstMainContentPlaying); } // EVENT HANDLERS @@ -113,125 +117,125 @@ export class AdScriptTHEOIntegration { const { duration } = event; const firstSecondOfMainContent = this.player.ads?.dai?.streamTimeForContentTime(1); const useDAITimeline = firstSecondOfMainContent && firstSecondOfMainContent !== 1; - this.mainContentDuration = duration + this.mainContentDuration = duration; if (duration === Infinity) { - this.mainContentLogPoints = [{reported: false, offset: this.player.currentTime + 1, name: "progress1"}] + this.mainContentLogPoints = [{ reported: false, offset: this.player.currentTime + 1, name: 'progress1' }]; } else { this.mainContentLogPoints = [ - {reported: false, offset: duration * 0.75, name: "thirdQuartile"}, - {reported: false, offset: duration * 0.5, name: "midpoint"}, - {reported: false, offset: duration * 0.25, name: "firstQuartile"}, - {reported: false, offset: useDAITimeline ? firstSecondOfMainContent : 1, name: "progress1"} - ] + { reported: false, offset: duration * 0.75, name: 'thirdQuartile' }, + { reported: false, offset: duration * 0.5, name: 'midpoint' }, + { reported: false, offset: duration * 0.25, name: 'firstQuartile' }, + { reported: false, offset: useDAITimeline ? firstSecondOfMainContent : 1, name: 'progress1' } + ]; } - } + }; private onSourceChange = (event: SourceChangeEvent) => { Logger.logEvent(event); - this.player.removeEventListener('playing', this.onFirstMainContentPlaying) - this.player.addEventListener('playing', this.onFirstMainContentPlaying) - this.mainContentLogPoints = [] - this.currentAdLogPoints = [] - this.currentAdMetadata = undefined - }; + this.player.removeEventListener('playing', this.onFirstMainContentPlaying); + this.player.addEventListener('playing', this.onFirstMainContentPlaying); + this.mainContentLogPoints = []; + this.currentAdLogPoints = []; + this.currentAdMetadata = undefined; + }; private onTimeUpdate = (event: TimeUpdateEvent) => { const { currentTime } = event; if (this.currentAdMetadata) { - this.maybeReportLogPoint(currentTime, this.currentAdMetadata, this.currentAdLogPoints) + this.maybeReportLogPoint(currentTime, this.currentAdMetadata, this.currentAdLogPoints); } else { - this.maybeReportLogPoint(currentTime, this.mainContentMetadata, this.mainContentLogPoints) + this.maybeReportLogPoint(currentTime, this.mainContentMetadata, this.mainContentLogPoints); } - } + }; private onFirstMainContentPlaying = () => { - const isBeforePreroll = this.player.ads?.scheduledAdBreaks.find(adBreak => adBreak.timeOffset === 0); + const isBeforePreroll = this.player.ads?.scheduledAdBreaks.find((adBreak) => adBreak.timeOffset === 0); if (this.player.ads?.playing || isBeforePreroll) return; - Logger.logAdScriptEvent("start",this.mainContentMetadata); - this.JHMT.push(["start", this.mainContentMetadata]); - this.player.removeEventListener("playing", this.onFirstMainContentPlaying); - } + Logger.logAdScriptEvent('start', this.mainContentMetadata); + this.JHMT.push(['start', this.mainContentMetadata]); + this.player.removeEventListener('playing', this.onFirstMainContentPlaying); + }; private onPlay = (event: PlayEvent) => { Logger.logEvent(event); this.reportPlayerState; - } + }; private onEnded = (event: EndedEvent) => { Logger.logEvent(event); - Logger.logAdScriptEvent("complete",this.mainContentMetadata); - this.JHMT.push(["complete", this.mainContentMetadata]); - } + Logger.logAdScriptEvent('complete', this.mainContentMetadata); + this.JHMT.push(['complete', this.mainContentMetadata]); + }; private onVolumeChange = (event: VolumeChangeEvent) => { Logger.logEvent(event); this.reportPlayerState(); - } + }; private onRateChange = (event: RateChangeEvent) => { Logger.logEvent(event); this.reportPlayerState(); - } + }; private onPresentationModeChange = (event: Event) => { Logger.logEvent(event); this.reportPlayerState(); - } + }; private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { Logger.logEvent(event); const { adBreak } = event; - const { timeOffset, integration } = adBreak + const { timeOffset, integration } = adBreak; this.currentAdLogPoints = []; this.currentAdMetadata = undefined; - if (integration === "google-dai" && timeOffset === 0) { - this.onFirstMainContentPlaying() + if (integration === 'google-dai' && timeOffset === 0) { + this.onFirstMainContentPlaying(); } - } + }; private onAdFirstQuartile = (event: AdEvent<'adfirstquartile'>) => { Logger.logEvent(event); - Logger.logAdScriptEvent("firstquartile",this.currentAdMetadata); - this.JHMT.push(["firstquartile", this.currentAdMetadata]) - } + Logger.logAdScriptEvent('firstquartile', this.currentAdMetadata); + this.JHMT.push(['firstquartile', this.currentAdMetadata]); + }; private onAdMidpoint = (event: AdEvent<'admidpoint'>) => { Logger.logEvent(event); - Logger.logAdScriptEvent("midpoint",this.currentAdMetadata); - this.JHMT.push(["midpoint", this.currentAdMetadata]) - } + Logger.logAdScriptEvent('midpoint', this.currentAdMetadata); + this.JHMT.push(['midpoint', this.currentAdMetadata]); + }; private onAdTirdQuartile = (event: AdEvent<'adthirdquartile'>) => { Logger.logEvent(event); - Logger.logAdScriptEvent("thirdquartile",this.currentAdMetadata); - this.JHMT.push(["thirdquartile", this.currentAdMetadata]) - } + Logger.logAdScriptEvent('thirdquartile', this.currentAdMetadata); + this.JHMT.push(['thirdquartile', this.currentAdMetadata]); + }; private onAdEnd = (event: AdEvent<'adend'>) => { Logger.logEvent(event); - Logger.logAdScriptEvent("complete",this.currentAdMetadata); - this.JHMT.push(["complete", this.currentAdMetadata]) - } + Logger.logAdScriptEvent('complete', this.currentAdMetadata); + this.JHMT.push(['complete', this.currentAdMetadata]); + }; private onAdBegin = (event: AdEvent<'adbegin'>) => { Logger.logEvent(event); - if (event.ad.type !== "linear") return - const adMetadataObject = this.buildAdMetadataObject(event) - this.currentAdMetadata = adMetadataObject - this.currentAdLogPoints = this.buildAdLogPoints(event.ad) - Logger.logAdScriptEvent("start",this.currentAdMetadata); - this.JHMT.push(["start",this.currentAdMetadata]) - } + if (event.ad.type !== 'linear') return; + const adMetadataObject = this.buildAdMetadataObject(event); + this.currentAdMetadata = adMetadataObject; + this.currentAdLogPoints = this.buildAdLogPoints(event.ad); + Logger.logAdScriptEvent('start', this.currentAdMetadata); + this.JHMT.push(['start', this.currentAdMetadata]); + }; private buildAdLogPoints = (ad: Ad) => { - const { duration } = ad - if (ad.adBreak.integration === "theo" && duration) { + const { duration } = ad; + if (ad.adBreak.integration === 'theo' && duration) { return [ - {reported: false, offset: duration * 0.75, name: "thirdQuartile"}, - {reported: false, offset: duration * 0.5, name: "midpoint"}, - {reported: false, offset: duration * 0.25, name: "firstQuartile"}, - {reported: false, offset: 1, name: "progress1"} - ] + { reported: false, offset: duration * 0.75, name: 'thirdQuartile' }, + { reported: false, offset: duration * 0.5, name: 'midpoint' }, + { reported: false, offset: duration * 0.25, name: 'firstQuartile' }, + { reported: false, offset: 1, name: 'progress1' } + ]; } - return [{reported: false, offset: 1, name: "progress1"}] - } + return [{ reported: false, offset: 1, name: 'progress1' }]; + }; private buildAdMetadataObject = (event: AdEvent<'adbegin'>): EmbeddedContentMetadata => { const { ad } = event; @@ -240,50 +244,54 @@ export class AdScriptTHEOIntegration { return { ...this.adProcessor(ad), type: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), - length: ad.duration?.toString() ?? "" - } + length: ad.duration?.toString() ?? '' + }; } return { - assetid: ad.id ?? "", + assetid: ad.id ?? '', type: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), - length: ad.duration?.toString() ?? "", - title: ad.integration?.includes("google") ? (ad as GoogleImaAd).title ?? "" : "", - asmea: "", - attributes: "" - } - } + length: ad.duration?.toString() ?? '', + title: ad.integration?.includes('google') ? (ad as GoogleImaAd).title ?? '' : '', + asmea: '', + attributes: '' + }; + }; private getAdType = (offset: number, duration: number, integration: string | undefined): EmbeddedContentType => { - if (offset === 0) return "preroll"; - if (offset === -1) return "postroll"; - if (duration - offset < 1 && integration === "google-dai") return "postroll" - if (this.mainContentDuration && this.mainContentDuration - offset < 1 ) return "postroll" - return "midroll" - } - + if (offset === 0) return 'preroll'; + if (offset === -1) return 'postroll'; + if (duration - offset < 1 && integration === 'google-dai') return 'postroll'; + if (this.mainContentDuration && this.mainContentDuration - offset < 1) return 'postroll'; + return 'midroll'; + }; + private reportPlayerState = () => { const playerState: PlayerState = { muted: this.player.muted ? 1 : 0, volume: this.player.volume * 100, triggeredByUser: this.player.autoplay ? 1 : 0, normalSpeed: this.player.playbackRate === 1 ? 1 : 0, - fullscreen: this.player.presentation.currentMode === "fullscreen" ? 1 : 0, + fullscreen: this.player.presentation.currentMode === 'fullscreen' ? 1 : 0, visibility: this.player.visibility.ratio * 100, width: this.player.element.clientWidth, height: this.player.element.clientHeight - } - Logger.logPlayerState(playerState) - this.JHMTApi.setPlayerState(playerState) - } + }; + Logger.logPlayerState(playerState); + this.JHMTApi.setPlayerState(playerState); + }; - private maybeReportLogPoint = (currentTime: number, metadata: MainVideoContentMetadata | EmbeddedContentMetadata, logPoints: LogPoint[]) => { - logPoints.forEach(logPoint => { - const { reported, offset, name } = logPoint + private maybeReportLogPoint = ( + currentTime: number, + metadata: MainVideoContentMetadata | EmbeddedContentMetadata, + logPoints: LogPoint[] + ) => { + logPoints.forEach((logPoint) => { + const { reported, offset, name } = logPoint; if (!reported && currentTime >= offset && currentTime < offset + 1) { - logPoint.reported = true - Logger.logAdScriptEvent(name,metadata); - this.JHMT.push([name,metadata]) + logPoint.reported = true; + Logger.logAdScriptEvent(name, metadata); + this.JHMT.push([name, metadata]); } - }) - } + }); + }; } diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index 3a53dfd4..68736568 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -1,31 +1,33 @@ -import { Event } from "theoplayer"; -import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from "../adscript/AdScript"; +import { Event } from 'theoplayer'; +import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from '../adscript/AdScript'; const LOG_THEOPLAYER_EVENTS = true; -const LOG_SETPLAYERSTATE = true -const LOG_SETMETADATA = true -const LOG_ADSCRIPT_EVENTS = true +const LOG_SETPLAYERSTATE = true; +const LOG_SETMETADATA = true; +const LOG_ADSCRIPT_EVENTS = true; const LOG_SETI12N = true; export class Logger { static logEvent = (event: Event) => { - if (LOG_THEOPLAYER_EVENTS) - console.log(`[ADSCRIPT - THEOplayer EVENTS] ${event.type} event`); - } + if (LOG_THEOPLAYER_EVENTS) console.log(`[ADSCRIPT - THEOplayer EVENTS] ${event.type} event`); + }; static logPlayerState = (playerState: PlayerState) => { - if (LOG_SETPLAYERSTATE) console.log(`[ADSCRIPT - setPlayerState]`,playerState); - } + if (LOG_SETPLAYERSTATE) console.log(`[ADSCRIPT - setPlayerState]`, playerState); + }; static logSetContentMetadata = (metadata: MainVideoContentMetadata) => { - if (LOG_SETMETADATA) console.log(`[ADSCRIPT - setContentMetadata]`,metadata); - } + if (LOG_SETMETADATA) console.log(`[ADSCRIPT - setContentMetadata]`, metadata); + }; - static logAdScriptEvent = (name: string, metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined) => { - if (LOG_ADSCRIPT_EVENTS) console.log(`[ADSCRIPT - EVENT] ${name}`,metadata) - } + static logAdScriptEvent = ( + name: string, + metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined + ) => { + if (LOG_ADSCRIPT_EVENTS) console.log(`[ADSCRIPT - EVENT] ${name}`, metadata); + }; static logsetI12n = (id: string, value: string) => { - if (LOG_SETI12N) console.log(`[ADSCRIPT - SET I12N] ${id}: ${value}`) - } -} \ No newline at end of file + if (LOG_SETI12N) console.log(`[ADSCRIPT - SET I12N] ${id}: ${value}`); + }; +} From 9520cc07a0185cfa85bcc3a62521c633de14d33e Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:28:33 +0200 Subject: [PATCH 24/59] Update docs --- adscript/src/integration/AdScriptConnector.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 11c3619b..0153b9a9 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -8,7 +8,7 @@ export class AdScriptConnector { private adscriptIntegration: AdScriptTHEOIntegration | undefined; /** - * Constructor for the THEOplayer AdScript connector + * Constructor for the THEOplayer AdScript connector. * @param player a THEOplayer instance reference * @param configuration a configuration object for the AdScript connector * @param metadata the MainVideoContentMetadata @@ -37,7 +37,11 @@ export class AdScriptConnector { }, 5000); } - updateMetadata(metadata: any): void { + /** + * Update the medata. + * @param metadata The MainVideoContentMetadata. + */ + updateMetadata(metadata: MainVideoContentMetadata): void { this.adscriptIntegration?.updateMetadata(metadata); } From 4254af414e9f406bdd2b48b52dc308a4dc148e86 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:28:53 +0200 Subject: [PATCH 25/59] Extract timeout to helper function --- adscript/src/integration/AdScriptConnector.ts | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 0153b9a9..9f888626 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -6,6 +6,10 @@ import { Logger } from '../utils/Logger'; export class AdScriptConnector { private adscriptIntegration: AdScriptTHEOIntegration | undefined; + private readonly player: ChromelessPlayer; + private readonly initialLoadTime: number; + private readonly configuration: AdScriptConfiguration; + private readonly metadata: MainVideoContentMetadata; /** * Constructor for the THEOplayer AdScript connector. @@ -15,28 +19,30 @@ export class AdScriptConnector { * @returns */ constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { - const interval = window.setInterval(() => { - if (typeof window.JHMTApi === 'object') { - window.clearInterval(interval); - const { i12n } = configuration; - for (const id in i12n) { - window.JHMTApi.setI12n(id, i12n[id]); - Logger.logsetI12n(id, i12n[id]); - } - this.adscriptIntegration = new AdScriptTHEOIntegration(player, configuration, metadata); - } - }, 20); - window.setTimeout(() => { - if (!window.JHMTApi) { - window.clearInterval(interval); - console.error( - 'JHMT API not found, make sure you included the script to initialize AdScript Measurement' - ); - return; - } - }, 5000); + this.player = player; + this.configuration = configuration; + this.metadata = metadata; + this.initialLoadTime = new Date().getTime(); + + setTimeout(this.createAdScriptIntegrationWhenApiIsAvailable, 20); } + private readonly createAdScriptIntegrationWhenApiIsAvailable = () => { + if (new Date().getTime() > this.initialLoadTime + 5_000) { + console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement.'); + } + if (typeof window.JHMTApi === 'object') { + const { i12n } = this.configuration; + for (const id in i12n) { + window.JHMTApi.setI12n(id, i12n[id]); + Logger.logsetI12n(id, i12n[id]); + } + this.adscriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration, this.metadata); + return; + } + setTimeout(this.createAdScriptIntegrationWhenApiIsAvailable, 20); + }; + /** * Update the medata. * @param metadata The MainVideoContentMetadata. From 64775913788759dfe949b012c377b74d9b2e5ccf Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:28:58 +0200 Subject: [PATCH 26/59] Update import --- adscript/src/integration/AdScriptConnector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 9f888626..90798e0f 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -1,4 +1,4 @@ -import { ChromelessPlayer } from 'theoplayer'; +import type { ChromelessPlayer } from 'theoplayer'; import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; import { AdScriptConfiguration } from './AdScriptConfiguration'; import { MainVideoContentMetadata } from '../adscript/AdScript'; From 2bd1868d1aeb4256821abfcb57b751a4a6611f23 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:29:42 +0200 Subject: [PATCH 27/59] Rename --- adscript/src/integration/AdScriptConnector.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 90798e0f..78d5ccf2 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -5,12 +5,13 @@ import { MainVideoContentMetadata } from '../adscript/AdScript'; import { Logger } from '../utils/Logger'; export class AdScriptConnector { - private adscriptIntegration: AdScriptTHEOIntegration | undefined; private readonly player: ChromelessPlayer; private readonly initialLoadTime: number; private readonly configuration: AdScriptConfiguration; private readonly metadata: MainVideoContentMetadata; + private adScriptIntegration: AdScriptTHEOIntegration | undefined; + /** * Constructor for the THEOplayer AdScript connector. * @param player a THEOplayer instance reference @@ -37,7 +38,7 @@ export class AdScriptConnector { window.JHMTApi.setI12n(id, i12n[id]); Logger.logsetI12n(id, i12n[id]); } - this.adscriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration, this.metadata); + this.adScriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration, this.metadata); return; } setTimeout(this.createAdScriptIntegrationWhenApiIsAvailable, 20); @@ -48,13 +49,13 @@ export class AdScriptConnector { * @param metadata The MainVideoContentMetadata. */ updateMetadata(metadata: MainVideoContentMetadata): void { - this.adscriptIntegration?.updateMetadata(metadata); + this.adScriptIntegration?.updateMetadata(metadata); } /** * Destroy */ destroy(): void { - this.adscriptIntegration?.destroy(); + this.adScriptIntegration?.destroy(); } } From 78954c8408ec9a154e55d18cbf88e98bc63d923a Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:31:00 +0200 Subject: [PATCH 28/59] Make readonly --- adscript/src/integration/AdScriptTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 018d1932..bb15a159 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -32,7 +32,7 @@ export class AdScriptTHEOIntegration { // References for constructor arguments private player: ChromelessPlayer; private debug: boolean; - private adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; + private readonly adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; private mainContentMetadata: MainVideoContentMetadata; private mainContentLogPoints: LogPoint[] = []; private mainContentDuration: number | undefined; From 872dbd19d7ceffe549860d37801aaf30cfaf6d93 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:31:21 +0200 Subject: [PATCH 29/59] Fix reporting player state in onPlay --- adscript/src/integration/AdScriptTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index bb15a159..0c5fbb24 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -158,7 +158,7 @@ export class AdScriptTHEOIntegration { private onPlay = (event: PlayEvent) => { Logger.logEvent(event); - this.reportPlayerState; + this.reportPlayerState(); }; private onEnded = (event: EndedEvent) => { From f1507124ebde10cce5c1729b2da5fef7119b1a7a Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:32:21 +0200 Subject: [PATCH 30/59] Import type only --- adscript/src/integration/AdScriptConfiguration.ts | 2 +- adscript/src/utils/Logger.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 8121056a..0a1edcef 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -1,4 +1,4 @@ -import { Ad } from 'theoplayer'; +import type { Ad } from 'theoplayer'; import { EmbeddedContentMetadata } from '../adscript/AdScript'; export interface AdScriptConfiguration { diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index 68736568..ed3a8e07 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -1,4 +1,4 @@ -import { Event } from 'theoplayer'; +import type { Event } from 'theoplayer'; import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from '../adscript/AdScript'; const LOG_THEOPLAYER_EVENTS = true; From ab58256d6f5e327fab4db3edf7449ca57e608db8 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:34:53 +0200 Subject: [PATCH 31/59] Remove more event listeners when destroyed --- adscript/src/integration/AdScriptTHEOIntegration.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 0c5fbb24..970471d0 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -107,6 +107,10 @@ export class AdScriptTHEOIntegration { if (this.player.ads) { this.player.ads.removeEventListener('adbreakend', this.onAdBreakEnd); //TODO this.player.ads.removeEventListener('adbegin', this.onAdBegin); //TODO + this.player.ads.removeEventListener('adfirstquartile', this.onAdFirstQuartile); + this.player.ads.removeEventListener('admidpoint', this.onAdMidpoint); + this.player.ads.removeEventListener('adthirdquartile', this.onAdTirdQuartile); + this.player.ads.removeEventListener('adend', this.onAdEnd); } this.player.removeEventListener('playing', this.onFirstMainContentPlaying); } From f24040f80203d5d339d553b086658fc18d9b1755 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:35:50 +0200 Subject: [PATCH 32/59] Re-order events for constancy --- adscript/src/integration/AdScriptTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 970471d0..dc274bd2 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -91,6 +91,7 @@ export class AdScriptTHEOIntegration { } private removeListeners(): void { + this.player.removeEventListener('playing', this.onFirstMainContentPlaying); this.player.removeEventListener('durationchange', this.onDurationChange); this.player.removeEventListener('sourcechange', this.onSourceChange); this.player.removeEventListener('timeupdate', this.onTimeUpdate); // TODO @@ -112,7 +113,6 @@ export class AdScriptTHEOIntegration { this.player.ads.removeEventListener('adthirdquartile', this.onAdTirdQuartile); this.player.ads.removeEventListener('adend', this.onAdEnd); } - this.player.removeEventListener('playing', this.onFirstMainContentPlaying); } // EVENT HANDLERS From 76878e10e156cae5f7b0b1f357981e94ed8bce76 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:38:47 +0200 Subject: [PATCH 33/59] Inline --- adscript/src/integration/AdScriptTHEOIntegration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index dc274bd2..cd179670 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -221,8 +221,7 @@ export class AdScriptTHEOIntegration { private onAdBegin = (event: AdEvent<'adbegin'>) => { Logger.logEvent(event); if (event.ad.type !== 'linear') return; - const adMetadataObject = this.buildAdMetadataObject(event); - this.currentAdMetadata = adMetadataObject; + this.currentAdMetadata = this.buildAdMetadataObject(event); this.currentAdLogPoints = this.buildAdLogPoints(event.ad); Logger.logAdScriptEvent('start', this.currentAdMetadata); this.JHMT.push(['start', this.currentAdMetadata]); From b1c3f6c46373b92fe997c3f4414b84a822744826 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 13:57:07 +0200 Subject: [PATCH 34/59] Dont create the integration if the connector was destroyed --- adscript/src/integration/AdScriptConnector.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 78d5ccf2..7909ac31 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -11,6 +11,7 @@ export class AdScriptConnector { private readonly metadata: MainVideoContentMetadata; private adScriptIntegration: AdScriptTHEOIntegration | undefined; + private destroyed = false; /** * Constructor for the THEOplayer AdScript connector. @@ -29,6 +30,11 @@ export class AdScriptConnector { } private readonly createAdScriptIntegrationWhenApiIsAvailable = () => { + if (this.destroyed) { + // The connector was destroyed before the API became available. + // Don't bother creating the integration. + return; + } if (new Date().getTime() > this.initialLoadTime + 5_000) { console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement.'); } @@ -56,6 +62,7 @@ export class AdScriptConnector { * Destroy */ destroy(): void { + this.destroyed = true; this.adScriptIntegration?.destroy(); } } From ccd807af340d41a4adf5bdf196696b2803676e6f Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 14:23:25 +0200 Subject: [PATCH 35/59] Run immediately --- adscript/src/integration/AdScriptConnector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 7909ac31..08f56d83 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -26,7 +26,7 @@ export class AdScriptConnector { this.metadata = metadata; this.initialLoadTime = new Date().getTime(); - setTimeout(this.createAdScriptIntegrationWhenApiIsAvailable, 20); + this.createAdScriptIntegrationWhenApiIsAvailable(); } private readonly createAdScriptIntegrationWhenApiIsAvailable = () => { From e1903e308bd18440543b1db8411a427c7fb6dc25 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 14:23:52 +0200 Subject: [PATCH 36/59] Break loop if API is not available after timeout --- adscript/src/integration/AdScriptConnector.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 08f56d83..dba6e8b7 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -37,6 +37,7 @@ export class AdScriptConnector { } if (new Date().getTime() > this.initialLoadTime + 5_000) { console.error('JHMT API not found, make sure you included the script to initialize AdScript Measurement.'); + return; } if (typeof window.JHMTApi === 'object') { const { i12n } = this.configuration; From 5b61f222b1cd5c90cb6eddfeb135ab5e771247bb Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 14:43:31 +0200 Subject: [PATCH 37/59] Update README --- adscript/README.md | 91 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/adscript/README.md b/adscript/README.md index bcde7966..ab3263c5 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -4,28 +4,103 @@ The AdScript connector provides a AdScript integration for THEOplayer. ## Installation -```sh +Install using your favorite package manager for Node (such as `npm` or `yarn`): + +### npm + +```bash npm install @theoplayer/adscript-connector-web ``` +### yarn + +```bash +yarn add @theoplayer/adscript-connector-web +``` + +## Prerequisites + First you need to initialize the AdScript Measurement by including the script in your app's html. ```html + ``` ## Usage -### Configuring the connector +First you need to add the Yospace connector to your app : + +* Add as a regular script + +```html + + + ``` -## Documentation +* Add as an ES2015 module + +```html + + +``` + +## Updating metadata + +If the metadata has changed during playback, you can update it with: + +```javascript +adScriptConnector.updateMetadata(newMetadata); +``` From 20541e7a3ef1cd386fa6ad9eaa81e828da41c14e Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 14:44:01 +0200 Subject: [PATCH 38/59] Run prettier on save --- .idea/prettier.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/prettier.xml b/.idea/prettier.xml index b0c1c68f..0c83ac4e 100644 --- a/.idea/prettier.xml +++ b/.idea/prettier.xml @@ -2,5 +2,6 @@ \ No newline at end of file From d2f14bbe2ee2820a334b398d84af65783f003e71 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 14:45:03 +0200 Subject: [PATCH 39/59] Fix README --- adscript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/README.md b/adscript/README.md index ab3263c5..e9d3fe18 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -32,7 +32,7 @@ First you need to initialize the AdScript Measurement by including the script in ## Usage -First you need to add the Yospace connector to your app : +First you need to add the AdScript connector to your app : * Add as a regular script From eb34bb2dcb4f8a9036a6ceccd6c401242df49dfc Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 15:12:44 +0200 Subject: [PATCH 40/59] Add docs on configuration --- .../src/integration/AdScriptConfiguration.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 0a1edcef..4c8c1f86 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -1,9 +1,28 @@ import type { Ad } from 'theoplayer'; import { EmbeddedContentMetadata } from '../adscript/AdScript'; +/** + * The configuration for the AdScript Connector. + */ export interface AdScriptConfiguration { + /** + * Integration ID you received from Nielsen representative + */ implementationId: string; - i12n: { [key: string]: string }; - debug?: boolean; + + /** + * Additional information settings (additional information) + * For more information, see the [Additional Information Settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. + */ + i12n?: { [key: string]: string }; + + /** + * An optional advertisement processor to receive metadata about the Ad. + */ adProcessor?: (ad: Ad) => EmbeddedContentMetadata; + + /** + * Whether the connector should log all actions. + */ + debug?: boolean; } From fcd589e0cadeef6b68fbe78238b0860cb06443a3 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 15:21:28 +0200 Subject: [PATCH 41/59] Rework logger --- adscript/src/integration/AdScriptConnector.ts | 6 -- .../integration/AdScriptTHEOIntegration.ts | 59 +++++++++++-------- adscript/src/utils/Logger.ts | 35 +++++------ 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index dba6e8b7..44399cab 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -2,7 +2,6 @@ import type { ChromelessPlayer } from 'theoplayer'; import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; import { AdScriptConfiguration } from './AdScriptConfiguration'; import { MainVideoContentMetadata } from '../adscript/AdScript'; -import { Logger } from '../utils/Logger'; export class AdScriptConnector { private readonly player: ChromelessPlayer; @@ -40,11 +39,6 @@ export class AdScriptConnector { return; } if (typeof window.JHMTApi === 'object') { - const { i12n } = this.configuration; - for (const id in i12n) { - window.JHMTApi.setI12n(id, i12n[id]); - Logger.logsetI12n(id, i12n[id]); - } this.adScriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration, this.metadata); return; } diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index cd179670..013de5af 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -31,7 +31,7 @@ interface LogPoint { export class AdScriptTHEOIntegration { // References for constructor arguments private player: ChromelessPlayer; - private debug: boolean; + private logger: Logger; private readonly adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; private mainContentMetadata: MainVideoContentMetadata; private mainContentLogPoints: LogPoint[] = []; @@ -46,18 +46,27 @@ export class AdScriptTHEOIntegration { constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { this.player = player; - this.debug = configuration.debug ?? false; + this.logger = new Logger(Boolean(configuration.debug)); this.adProcessor = configuration?.adProcessor; this.mainContentMetadata = metadata; - Logger.logSetContentMetadata(this.mainContentMetadata); + + // Set the additional information about the logged user. + for (const id in configuration.i12n) { + this.logger.onSetI12N(id, configuration.i12n[id]); + this.JHMTApi.setI12n(id, configuration.i12n[id]); + } + + // Set the metadata before attaching event listeners. + this.logger.onSetMainVideoContentMetadata(this.mainContentMetadata); this.JHMTApi.setContentMetadata(this.mainContentMetadata); + this.reportPlayerState(); this.addListeners(); } public updateMetadata(metadata: MainVideoContentMetadata) { this.mainContentMetadata = metadata; - Logger.logSetContentMetadata(this.mainContentMetadata); + this.logger.onSetMainVideoContentMetadata(this.mainContentMetadata); this.JHMTApi.setContentMetadata(this.mainContentMetadata); } @@ -135,7 +144,7 @@ export class AdScriptTHEOIntegration { }; private onSourceChange = (event: SourceChangeEvent) => { - Logger.logEvent(event); + this.logger.onEvent(event); this.player.removeEventListener('playing', this.onFirstMainContentPlaying); this.player.addEventListener('playing', this.onFirstMainContentPlaying); this.mainContentLogPoints = []; @@ -155,39 +164,39 @@ export class AdScriptTHEOIntegration { private onFirstMainContentPlaying = () => { const isBeforePreroll = this.player.ads?.scheduledAdBreaks.find((adBreak) => adBreak.timeOffset === 0); if (this.player.ads?.playing || isBeforePreroll) return; - Logger.logAdScriptEvent('start', this.mainContentMetadata); + this.logger.onAdScriptEvent('start', this.mainContentMetadata); this.JHMT.push(['start', this.mainContentMetadata]); this.player.removeEventListener('playing', this.onFirstMainContentPlaying); }; private onPlay = (event: PlayEvent) => { - Logger.logEvent(event); + this.logger.onEvent(event); this.reportPlayerState(); }; private onEnded = (event: EndedEvent) => { - Logger.logEvent(event); - Logger.logAdScriptEvent('complete', this.mainContentMetadata); + this.logger.onEvent(event); + this.logger.onAdScriptEvent('complete', this.mainContentMetadata); this.JHMT.push(['complete', this.mainContentMetadata]); }; private onVolumeChange = (event: VolumeChangeEvent) => { - Logger.logEvent(event); + this.logger.onEvent(event); this.reportPlayerState(); }; private onRateChange = (event: RateChangeEvent) => { - Logger.logEvent(event); + this.logger.onEvent(event); this.reportPlayerState(); }; private onPresentationModeChange = (event: Event) => { - Logger.logEvent(event); + this.logger.onEvent(event); this.reportPlayerState(); }; private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { - Logger.logEvent(event); + this.logger.onEvent(event); const { adBreak } = event; const { timeOffset, integration } = adBreak; this.currentAdLogPoints = []; @@ -198,32 +207,32 @@ export class AdScriptTHEOIntegration { }; private onAdFirstQuartile = (event: AdEvent<'adfirstquartile'>) => { - Logger.logEvent(event); - Logger.logAdScriptEvent('firstquartile', this.currentAdMetadata); + this.logger.onEvent(event); + this.logger.onAdScriptEvent('firstquartile', this.currentAdMetadata); this.JHMT.push(['firstquartile', this.currentAdMetadata]); }; private onAdMidpoint = (event: AdEvent<'admidpoint'>) => { - Logger.logEvent(event); - Logger.logAdScriptEvent('midpoint', this.currentAdMetadata); + this.logger.onEvent(event); + this.logger.onAdScriptEvent('midpoint', this.currentAdMetadata); this.JHMT.push(['midpoint', this.currentAdMetadata]); }; private onAdTirdQuartile = (event: AdEvent<'adthirdquartile'>) => { - Logger.logEvent(event); - Logger.logAdScriptEvent('thirdquartile', this.currentAdMetadata); + this.logger.onEvent(event); + this.logger.onAdScriptEvent('thirdquartile', this.currentAdMetadata); this.JHMT.push(['thirdquartile', this.currentAdMetadata]); }; private onAdEnd = (event: AdEvent<'adend'>) => { - Logger.logEvent(event); - Logger.logAdScriptEvent('complete', this.currentAdMetadata); + this.logger.onEvent(event); + this.logger.onAdScriptEvent('complete', this.currentAdMetadata); this.JHMT.push(['complete', this.currentAdMetadata]); }; private onAdBegin = (event: AdEvent<'adbegin'>) => { - Logger.logEvent(event); + this.logger.onEvent(event); if (event.ad.type !== 'linear') return; this.currentAdMetadata = this.buildAdMetadataObject(event); this.currentAdLogPoints = this.buildAdLogPoints(event.ad); - Logger.logAdScriptEvent('start', this.currentAdMetadata); + this.logger.onAdScriptEvent('start', this.currentAdMetadata); this.JHMT.push(['start', this.currentAdMetadata]); }; @@ -279,7 +288,7 @@ export class AdScriptTHEOIntegration { width: this.player.element.clientWidth, height: this.player.element.clientHeight }; - Logger.logPlayerState(playerState); + this.logger.onPlayerStateChange(playerState); this.JHMTApi.setPlayerState(playerState); }; @@ -292,7 +301,7 @@ export class AdScriptTHEOIntegration { const { reported, offset, name } = logPoint; if (!reported && currentTime >= offset && currentTime < offset + 1) { logPoint.reported = true; - Logger.logAdScriptEvent(name, metadata); + this.logger.onAdScriptEvent(name, metadata); this.JHMT.push([name, metadata]); } }); diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index ed3a8e07..46a7a9ed 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -1,33 +1,30 @@ import type { Event } from 'theoplayer'; import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from '../adscript/AdScript'; -const LOG_THEOPLAYER_EVENTS = true; -const LOG_SETPLAYERSTATE = true; -const LOG_SETMETADATA = true; -const LOG_ADSCRIPT_EVENTS = true; -const LOG_SETI12N = true; - export class Logger { - static logEvent = (event: Event) => { - if (LOG_THEOPLAYER_EVENTS) console.log(`[ADSCRIPT - THEOplayer EVENTS] ${event.type} event`); + private debug: boolean; + + constructor(debug: boolean = false) { + this.debug = debug; + } + + onEvent = (event: Event) => { + if (this.debug) console.log(`[ADSCRIPT - THEOplayer EVENTS] ${event.type} event`); }; - static logPlayerState = (playerState: PlayerState) => { - if (LOG_SETPLAYERSTATE) console.log(`[ADSCRIPT - setPlayerState]`, playerState); + onPlayerStateChange = (playerState: PlayerState) => { + if (this.debug) console.log(`[ADSCRIPT - setPlayerState]`, playerState); }; - static logSetContentMetadata = (metadata: MainVideoContentMetadata) => { - if (LOG_SETMETADATA) console.log(`[ADSCRIPT - setContentMetadata]`, metadata); + onSetMainVideoContentMetadata = (metadata: MainVideoContentMetadata) => { + if (this.debug) console.log(`[ADSCRIPT - setContentMetadata]`, metadata); }; - static logAdScriptEvent = ( - name: string, - metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined - ) => { - if (LOG_ADSCRIPT_EVENTS) console.log(`[ADSCRIPT - EVENT] ${name}`, metadata); + onAdScriptEvent = (name: string, metadata: MainVideoContentMetadata | EmbeddedContentMetadata | undefined) => { + if (this.debug) console.log(`[ADSCRIPT - EVENT] ${name}`, metadata); }; - static logsetI12n = (id: string, value: string) => { - if (LOG_SETI12N) console.log(`[ADSCRIPT - SET I12N] ${id}: ${value}`); + onSetI12N = (id: string, value: string) => { + if (this.debug) console.log(`[ADSCRIPT - SET I12N] ${id}: ${value}`); }; } From 68f37f98e17f9375b736022402c6c50063289441 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 15:26:17 +0200 Subject: [PATCH 42/59] Improve docs --- adscript/src/integration/AdScriptConfiguration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 4c8c1f86..9c03e608 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -6,12 +6,12 @@ import { EmbeddedContentMetadata } from '../adscript/AdScript'; */ export interface AdScriptConfiguration { /** - * Integration ID you received from Nielsen representative + * Integration ID you received from Nielsen representative. */ implementationId: string; /** - * Additional information settings (additional information) + * Additional information about logged user (customerID, deviceID, profileID) from client´s database. * For more information, see the [Additional Information Settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. */ i12n?: { [key: string]: string }; From 9c8d27e0ee1d38c9951de98dcb3b1075e36fa4f4 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 19 Jul 2024 15:29:29 +0200 Subject: [PATCH 43/59] Add AdScript to landing page --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8ef22b61..e30f04b7 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,14 @@ Using the available connectors allows you to augment the features delivered thro ## Available Connectors -| Connector | npm package | Source code | -|:----------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------| -| CMCD | [![@theoplayer/cmcd-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcmcd-connector-web?label=%40theoplayer%2Fcmcd-connector-web)](https://npmjs.com/package/@theoplayer/cmcd-connector-web) | [cmcd](https://github.com/THEOplayer/web-connectors/tree/main/cmcd) | -| Comscore | [![@theoplayer/comscore-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcomscore-connector-web?label=%40theoplayer%2Fcomscore-connector-web)](https://npmjs.com/package/@theoplayer/comscore-connector-web) | [comscore](https://github.com/THEOplayer/web-connectors/tree/main/comscore) | -| Conviva | [![@theoplayer/conviva-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fconviva-connector-web?label=%40theoplayer%2Fconviva-connector-web)](https://npmjs.com/package/@theoplayer/conviva-connector-web) | [conviva](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | -| Nielsen | [![@theoplayer/nielsen-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fnielsen-connector-web?label=%40theoplayer%2Fnielsen-connector-web)](https://npmjs.com/package/@theoplayer/nielsen-connector-web) | [nielsen](https://github.com/THEOplayer/web-connectors/tree/main/nielsen) | -| Yospace | [![@theoplayer/yospace-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fyospace-connector-web?label=%40theoplayer%2Fyospace-connector-web)](https://npmjs.com/package/@theoplayer/yospace-connector-web) | [yospace](https://github.com/THEOplayer/web-connectors/tree/main/yospace) | +| Connector | npm package | Source code | +|:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------| +| AdScript | [![@theoplayer/adscript-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fadscript-connector-web?label=%40theoplayer%2Fadscript-connector-web)](https://npmjs.com/package/@theoplayer/adscript-connector-web) | [adscript](https://github.com/THEOplayer/web-connectors/tree/main/adscript) | +| CMCD | [![@theoplayer/cmcd-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcmcd-connector-web?label=%40theoplayer%2Fcmcd-connector-web)](https://npmjs.com/package/@theoplayer/cmcd-connector-web) | [cmcd](https://github.com/THEOplayer/web-connectors/tree/main/cmcd) | +| Comscore | [![@theoplayer/comscore-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcomscore-connector-web?label=%40theoplayer%2Fcomscore-connector-web)](https://npmjs.com/package/@theoplayer/comscore-connector-web) | [comscore](https://github.com/THEOplayer/web-connectors/tree/main/comscore) | +| Conviva | [![@theoplayer/conviva-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fconviva-connector-web?label=%40theoplayer%2Fconviva-connector-web)](https://npmjs.com/package/@theoplayer/conviva-connector-web) | [conviva](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | +| Nielsen | [![@theoplayer/nielsen-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fnielsen-connector-web?label=%40theoplayer%2Fnielsen-connector-web)](https://npmjs.com/package/@theoplayer/nielsen-connector-web) | [nielsen](https://github.com/THEOplayer/web-connectors/tree/main/nielsen) | +| Yospace | [![@theoplayer/yospace-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fyospace-connector-web?label=%40theoplayer%2Fyospace-connector-web)](https://npmjs.com/package/@theoplayer/yospace-connector-web) | [yospace](https://github.com/THEOplayer/web-connectors/tree/main/yospace) | ## License From 314a22c39e831bccb83bcc5db18e87cf1fef9e01 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 13:05:39 +0200 Subject: [PATCH 44/59] Load AdScript intenally --- adscript/README.md | 12 ----- adscript/src/integration/AdScriptConnector.ts | 17 +++++-- .../integration/AdScriptTHEOIntegration.ts | 24 ++++++--- adscript/src/integration/LoadAdScriptSDK.ts | 51 +++++++++++++++++++ 4 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 adscript/src/integration/LoadAdScriptSDK.ts diff --git a/adscript/README.md b/adscript/README.md index e9d3fe18..2cfc1fe1 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -18,18 +18,6 @@ npm install @theoplayer/adscript-connector-web yarn add @theoplayer/adscript-connector-web ``` -## Prerequisites - -First you need to initialize the AdScript Measurement by including the script in your app's html. - -```html - - -``` - ## Usage First you need to add the AdScript connector to your app : diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 44399cab..9ea97547 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -2,6 +2,7 @@ import type { ChromelessPlayer } from 'theoplayer'; import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; import { AdScriptConfiguration } from './AdScriptConfiguration'; import { MainVideoContentMetadata } from '../adscript/AdScript'; +import { loadAdScriptSDK } from './LoadAdScriptSDK'; export class AdScriptConnector { private readonly player: ChromelessPlayer; @@ -16,14 +17,21 @@ export class AdScriptConnector { * Constructor for the THEOplayer AdScript connector. * @param player a THEOplayer instance reference * @param configuration a configuration object for the AdScript connector - * @param metadata the MainVideoContentMetadata + * @param initialMetadata the MainVideoContentMetadata * @returns */ - constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { + constructor( + player: ChromelessPlayer, + configuration: AdScriptConfiguration, + initialMetadata: MainVideoContentMetadata + ) { this.player = player; this.configuration = configuration; - this.metadata = metadata; + this.metadata = initialMetadata; + + // This loads the external AdScript SDK script. This is not immediately available, so we start a timer. this.initialLoadTime = new Date().getTime(); + loadAdScriptSDK(configuration.implementationId); this.createAdScriptIntegrationWhenApiIsAvailable(); } @@ -47,6 +55,7 @@ export class AdScriptConnector { /** * Update the medata. + * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. * @param metadata The MainVideoContentMetadata. */ updateMetadata(metadata: MainVideoContentMetadata): void { @@ -54,7 +63,7 @@ export class AdScriptConnector { } /** - * Destroy + * Destroy the connector. */ destroy(): void { this.destroyed = true; diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 013de5af..c0c78374 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -44,21 +44,23 @@ export class AdScriptTHEOIntegration { private JHMTApi = window.JHMTApi; private JHMT = window.JHMT; - constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration, metadata: MainVideoContentMetadata) { + constructor( + player: ChromelessPlayer, + configuration: AdScriptConfiguration, + initialMetadata: MainVideoContentMetadata + ) { this.player = player; this.logger = new Logger(Boolean(configuration.debug)); this.adProcessor = configuration?.adProcessor; - this.mainContentMetadata = metadata; + this.mainContentMetadata = initialMetadata; // Set the additional information about the logged user. - for (const id in configuration.i12n) { - this.logger.onSetI12N(id, configuration.i12n[id]); - this.JHMTApi.setI12n(id, configuration.i12n[id]); + if (configuration.i12n) { + this.updateUser(configuration.i12n); } // Set the metadata before attaching event listeners. - this.logger.onSetMainVideoContentMetadata(this.mainContentMetadata); - this.JHMTApi.setContentMetadata(this.mainContentMetadata); + this.updateMetadata(initialMetadata); this.reportPlayerState(); this.addListeners(); @@ -70,6 +72,14 @@ export class AdScriptTHEOIntegration { this.JHMTApi.setContentMetadata(this.mainContentMetadata); } + public updateUser(i12n: { [key: string]: string }): void { + // Set the additional information about the logged user. + for (const id in i12n) { + this.logger.onSetI12N(id, i12n[id]); + this.JHMTApi.setI12n(id, i12n[id]); + } + } + public destroy() { this.removeListeners(); } diff --git a/adscript/src/integration/LoadAdScriptSDK.ts b/adscript/src/integration/LoadAdScriptSDK.ts new file mode 100644 index 00000000..0c7dc74a --- /dev/null +++ b/adscript/src/integration/LoadAdScriptSDK.ts @@ -0,0 +1,51 @@ +// @ts-nocheck + +/** + * This function loads the AdScript SDK. + * This comes directly from the AdScript documentation: https://adscript.admosphere.cz/en_adScript_browser.html + */ +export function loadAdScriptSDK(implementationId: string) { + !(function (j, h, m, t, c, z) { + c = c || 'JHMT'; + j[c] = j[c] || []; + j['JHMTApiProtocol'] = 'https:'; + z = z || 3; + + var i = (z % 3) + 1, + a = arguments.callee, + b = h.createElement('script'); + + (b.async = !0), + b.readyState + ? (b.onreadystatechange = function () { + ('loaded' !== b.readyState && 'complete' !== b.readyState) || + ((b.onreadystataechange = null), j.JHMTApi.init(c, m, t)); + }) + : (b.onload = function () { + j.JHMTApi.init(c, m, t); + }), + (b.src = j['JHMTApiProtocol'] + '//cm' + i + '.jhmt.cz/api.js'), + (b.onerror = function () { + b.parentNode.removeChild(b); + z++; + i = (z % 3) + 1; + a(j, h, m, t, c, i); + }), + h.getElementsByTagName('head')[0].appendChild(b); + + try { + var it = setInterval(function () { + if (typeof j.JHMTApi !== 'undefined') { + clearInterval(it); + } else { + b.parentNode.removeChild(b); + z++; + i = (z % 3) + 1; + a(j, h, m, t, c, i); + } + }, 1e3); + } catch (e) { + console.log('JHMT: ' + e); + } + })(window, document, implementationId); +} From 7b150aa8af603f9ac13f76d5462cc31ab7446146 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 13:05:50 +0200 Subject: [PATCH 45/59] Expose option to update user data --- adscript/README.md | 8 ++++++++ adscript/src/integration/AdScriptConnector.ts | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/adscript/README.md b/adscript/README.md index 2cfc1fe1..d9971f5e 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -92,3 +92,11 @@ If the metadata has changed during playback, you can update it with: ```javascript adScriptConnector.updateMetadata(newMetadata); ``` + +## Updating userInfo + +If the user info has changed during playback, you can update it with: + +```javascript +adScriptConnector.updateUser(i12n); +``` \ No newline at end of file diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 9ea97547..e8be118d 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -62,6 +62,15 @@ export class AdScriptConnector { this.adScriptIntegration?.updateMetadata(metadata); } + /** + * Updates the additional information about logged user (customerID, deviceID, profileID, ...) from client´s database. + * For more information, see the [Additional Information Settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. + * @param i12n The Additional Information + */ + updateUser(i12n: { [key: string]: string }): void { + this.adScriptIntegration?.updateUser(i12n); + } + /** * Destroy the connector. */ From c1e60a27770ed332b7e77299fda9018984d171dd Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 13:08:24 +0200 Subject: [PATCH 46/59] Cleanup --- adscript/src/integration/AdScriptTHEOIntegration.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index c0c78374..06e36686 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -29,7 +29,6 @@ interface LogPoint { } export class AdScriptTHEOIntegration { - // References for constructor arguments private player: ChromelessPlayer; private logger: Logger; private readonly adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; @@ -39,8 +38,6 @@ export class AdScriptTHEOIntegration { private currentAdMetadata: EmbeddedContentMetadata | undefined; private currentAdLogPoints: LogPoint[] = []; - private latestReportedEvent: string | undefined; - private JHMTApi = window.JHMTApi; private JHMT = window.JHMT; @@ -134,7 +131,6 @@ export class AdScriptTHEOIntegration { } } - // EVENT HANDLERS private onDurationChange = (event: DurationChangeEvent) => { if (this.player.ads?.playing || this.mainContentLogPoints.length) return; const { duration } = event; From 76344f9c6bfd464438f6489525aa070c9eba7785 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 13:09:01 +0200 Subject: [PATCH 47/59] Add readonly --- adscript/src/utils/Logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index 46a7a9ed..d9858384 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -2,7 +2,7 @@ import type { Event } from 'theoplayer'; import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from '../adscript/AdScript'; export class Logger { - private debug: boolean; + private readonly debug: boolean; constructor(debug: boolean = false) { this.debug = debug; From 62513acfaeba9ce35d54700ff660e6685032ae1e Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 14:00:08 +0200 Subject: [PATCH 48/59] Fix type --- adscript/src/adscript/AdScript.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts index 14fb9817..ac3c3264 100644 --- a/adscript/src/adscript/AdScript.d.ts +++ b/adscript/src/adscript/AdScript.d.ts @@ -34,7 +34,7 @@ interface EmbeddedContentMetadata { interface StaticContentMetadata { assetid: string; - type: MainVideoContentType; + type: StaticContentType; sec1: string; sec2: string; sec3: string; From 34ffde1a91872a46a2982fa1305a14cfe8e27673 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 14:00:25 +0200 Subject: [PATCH 49/59] Add and update documentation about metadata --- adscript/src/adscript/AdScript.d.ts | 9 ++++++++- adscript/src/integration/AdScriptConnector.ts | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts index ac3c3264..642b8905 100644 --- a/adscript/src/adscript/AdScript.d.ts +++ b/adscript/src/adscript/AdScript.d.ts @@ -11,6 +11,10 @@ export type MainVideoContentType = 'content'; export type EmbeddedContentType = 'preroll' | 'midroll' | 'postroll'; export type StaticContentType = 'static'; +/** + * The main content information settings. + * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section in the AdScript documentation. + */ export interface MainVideoContentMetadata { assetid: string; type: MainVideoContentType; @@ -23,7 +27,10 @@ export interface MainVideoContentMetadata { attributes: string; } -interface EmbeddedContentMetadata { +/** + * The embedded content metadata, about the currently playing ad. + */ +export interface EmbeddedContentMetadata { assetid: string; type: EmbeddedContentType; length: string; diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index e8be118d..c5a3818a 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -54,8 +54,9 @@ export class AdScriptConnector { }; /** - * Update the medata. - * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. + * Update the main content information settings. + * This method must be called every time the main video content on the currently displayed page changes. + * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section in the AdScript documentation. * @param metadata The MainVideoContentMetadata. */ updateMetadata(metadata: MainVideoContentMetadata): void { From 4e4736db591bec197295c73a5ff6e420f12010d9 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 14:00:28 +0200 Subject: [PATCH 50/59] Format --- adscript/src/adscript/AdScript.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts index 642b8905..5b5628d1 100644 --- a/adscript/src/adscript/AdScript.d.ts +++ b/adscript/src/adscript/AdScript.d.ts @@ -1,4 +1,5 @@ export type JHMTApiProtocol = 'https:' | 'http:' | 'file:'; + interface I12n { i1: string; i2: string; @@ -77,6 +78,8 @@ declare global { export interface JHMTApi { setI12n(i12n: I12n); + setContentMetadata(contentMetadata: ContentMetadata); + setPlayerState(playerState: PlayerState); } From 45322582d14df59685805013b4832fad56296bab Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 14:47:37 +0200 Subject: [PATCH 51/59] Tweak API to use metadata from configuration --- .../src/integration/AdScriptConfiguration.ts | 7 ++++++ adscript/src/integration/AdScriptConnector.ts | 23 +++++++++++-------- .../integration/AdScriptTHEOIntegration.ts | 22 ++++++------------ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 9c03e608..2f23e86d 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -10,6 +10,13 @@ export interface AdScriptConfiguration { */ implementationId: string; + /** + * The initial main content information settings. + * Metadata of the main video content needs to be set before the first measured event occurs. + * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section in the AdScript documentation. + */ + metadata: MainVideoContentMetadata; + /** * Additional information about logged user (customerID, deviceID, profileID) from client´s database. * For more information, see the [Additional Information Settings](https://adscript.admosphere.cz/en_adScript_browser.html) section. diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index c5a3818a..3be31f9e 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -8,7 +8,9 @@ export class AdScriptConnector { private readonly player: ChromelessPlayer; private readonly initialLoadTime: number; private readonly configuration: AdScriptConfiguration; - private readonly metadata: MainVideoContentMetadata; + + private metadata: MainVideoContentMetadata; + private i12n: { [key: string]: string } | undefined; private adScriptIntegration: AdScriptTHEOIntegration | undefined; private destroyed = false; @@ -17,17 +19,13 @@ export class AdScriptConnector { * Constructor for the THEOplayer AdScript connector. * @param player a THEOplayer instance reference * @param configuration a configuration object for the AdScript connector - * @param initialMetadata the MainVideoContentMetadata * @returns */ - constructor( - player: ChromelessPlayer, - configuration: AdScriptConfiguration, - initialMetadata: MainVideoContentMetadata - ) { + constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration) { this.player = player; this.configuration = configuration; - this.metadata = initialMetadata; + this.metadata = configuration.metadata; + this.i12n = configuration.i12n; // This loads the external AdScript SDK script. This is not immediately available, so we start a timer. this.initialLoadTime = new Date().getTime(); @@ -47,7 +45,12 @@ export class AdScriptConnector { return; } if (typeof window.JHMTApi === 'object') { - this.adScriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration, this.metadata); + this.adScriptIntegration = new AdScriptTHEOIntegration(this.player, this.configuration); + if (this.i12n) { + this.adScriptIntegration.updateUser(this.i12n); + } + this.adScriptIntegration.updateMetadata(this.metadata); + this.adScriptIntegration.start(); return; } setTimeout(this.createAdScriptIntegrationWhenApiIsAvailable, 20); @@ -60,6 +63,7 @@ export class AdScriptConnector { * @param metadata The MainVideoContentMetadata. */ updateMetadata(metadata: MainVideoContentMetadata): void { + this.metadata = metadata; this.adScriptIntegration?.updateMetadata(metadata); } @@ -69,6 +73,7 @@ export class AdScriptConnector { * @param i12n The Additional Information */ updateUser(i12n: { [key: string]: string }): void { + this.i12n = i12n; this.adScriptIntegration?.updateUser(i12n); } diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 06e36686..5839031d 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -32,7 +32,7 @@ export class AdScriptTHEOIntegration { private player: ChromelessPlayer; private logger: Logger; private readonly adProcessor: ((ad: Ad) => EmbeddedContentMetadata) | undefined; - private mainContentMetadata: MainVideoContentMetadata; + private mainContentMetadata: MainVideoContentMetadata | undefined; private mainContentLogPoints: LogPoint[] = []; private mainContentDuration: number | undefined; private currentAdMetadata: EmbeddedContentMetadata | undefined; @@ -41,24 +41,16 @@ export class AdScriptTHEOIntegration { private JHMTApi = window.JHMTApi; private JHMT = window.JHMT; - constructor( - player: ChromelessPlayer, - configuration: AdScriptConfiguration, - initialMetadata: MainVideoContentMetadata - ) { + constructor(player: ChromelessPlayer, configuration: AdScriptConfiguration) { this.player = player; this.logger = new Logger(Boolean(configuration.debug)); this.adProcessor = configuration?.adProcessor; - this.mainContentMetadata = initialMetadata; + } - // Set the additional information about the logged user. - if (configuration.i12n) { - this.updateUser(configuration.i12n); + public start() { + if (this.mainContentMetadata === undefined) { + throw Error('Metadata of the main video content needs to be set before the first measured event occurs.'); } - - // Set the metadata before attaching event listeners. - this.updateMetadata(initialMetadata); - this.reportPlayerState(); this.addListeners(); } @@ -163,7 +155,7 @@ export class AdScriptTHEOIntegration { if (this.currentAdMetadata) { this.maybeReportLogPoint(currentTime, this.currentAdMetadata, this.currentAdLogPoints); } else { - this.maybeReportLogPoint(currentTime, this.mainContentMetadata, this.mainContentLogPoints); + this.maybeReportLogPoint(currentTime, this.mainContentMetadata!, this.mainContentLogPoints); } }; From 041ca6abe67ccae5b05ef45e3beca8c649f09ab2 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 22 Jul 2024 14:47:50 +0200 Subject: [PATCH 52/59] Move interfaces --- adscript/src/adscript/AdScript.d.ts | 28 ------------------ .../src/integration/AdScriptConfiguration.ts | 29 ++++++++++++++++++- adscript/src/integration/AdScriptConnector.ts | 3 +- .../integration/AdScriptTHEOIntegration.ts | 11 ++----- adscript/src/utils/Logger.ts | 3 +- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/adscript/src/adscript/AdScript.d.ts b/adscript/src/adscript/AdScript.d.ts index 5b5628d1..e64ae1b0 100644 --- a/adscript/src/adscript/AdScript.d.ts +++ b/adscript/src/adscript/AdScript.d.ts @@ -12,34 +12,6 @@ export type MainVideoContentType = 'content'; export type EmbeddedContentType = 'preroll' | 'midroll' | 'postroll'; export type StaticContentType = 'static'; -/** - * The main content information settings. - * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section in the AdScript documentation. - */ -export interface MainVideoContentMetadata { - assetid: string; - type: MainVideoContentType; - program: string; - title: string; - length: string; - crossId: string; - livestream: string; - channelId: string; - attributes: string; -} - -/** - * The embedded content metadata, about the currently playing ad. - */ -export interface EmbeddedContentMetadata { - assetid: string; - type: EmbeddedContentType; - length: string; - title: string; - asmea: string; - attributes: string; -} - interface StaticContentMetadata { assetid: string; type: StaticContentType; diff --git a/adscript/src/integration/AdScriptConfiguration.ts b/adscript/src/integration/AdScriptConfiguration.ts index 2f23e86d..5d1b9297 100644 --- a/adscript/src/integration/AdScriptConfiguration.ts +++ b/adscript/src/integration/AdScriptConfiguration.ts @@ -1,5 +1,32 @@ import type { Ad } from 'theoplayer'; -import { EmbeddedContentMetadata } from '../adscript/AdScript'; + +/** + * The main content information settings. + * For more information, see the [main content information settings](https://adscript.admosphere.cz/en_adScript_browser.html) section in the AdScript documentation. + */ +export interface MainVideoContentMetadata { + assetid: string; + type: 'content'; + program: string; + title: string; + length: string; + crossId: string; + livestream: string; + channelId: string; + attributes: string; +} + +/** + * The embedded content metadata, about the currently playing ad. + */ +export interface EmbeddedContentMetadata { + assetid: string; + type: 'preroll' | 'midroll' | 'postroll'; + length: string; + title: string; + asmea: string; + attributes: string; +} /** * The configuration for the AdScript Connector. diff --git a/adscript/src/integration/AdScriptConnector.ts b/adscript/src/integration/AdScriptConnector.ts index 3be31f9e..bc1ebb15 100644 --- a/adscript/src/integration/AdScriptConnector.ts +++ b/adscript/src/integration/AdScriptConnector.ts @@ -1,7 +1,6 @@ import type { ChromelessPlayer } from 'theoplayer'; import { AdScriptTHEOIntegration } from './AdScriptTHEOIntegration'; -import { AdScriptConfiguration } from './AdScriptConfiguration'; -import { MainVideoContentMetadata } from '../adscript/AdScript'; +import { AdScriptConfiguration, MainVideoContentMetadata } from './AdScriptConfiguration'; import { loadAdScriptSDK } from './LoadAdScriptSDK'; export class AdScriptConnector { diff --git a/adscript/src/integration/AdScriptTHEOIntegration.ts b/adscript/src/integration/AdScriptTHEOIntegration.ts index 5839031d..fcd25ebc 100644 --- a/adscript/src/integration/AdScriptTHEOIntegration.ts +++ b/adscript/src/integration/AdScriptTHEOIntegration.ts @@ -13,13 +13,8 @@ import type { TimeUpdateEvent, VolumeChangeEvent } from 'theoplayer'; -import { AdScriptConfiguration } from './AdScriptConfiguration'; -import { - EmbeddedContentMetadata, - EmbeddedContentType, - MainVideoContentMetadata, - PlayerState -} from './../adscript/AdScript'; +import { AdScriptConfiguration, EmbeddedContentMetadata, MainVideoContentMetadata } from './AdScriptConfiguration'; +import { EmbeddedContentType } from './../adscript/AdScript'; import { Logger } from '../utils/Logger'; interface LogPoint { @@ -276,7 +271,7 @@ export class AdScriptTHEOIntegration { }; private reportPlayerState = () => { - const playerState: PlayerState = { + const playerState = { muted: this.player.muted ? 1 : 0, volume: this.player.volume * 100, triggeredByUser: this.player.autoplay ? 1 : 0, diff --git a/adscript/src/utils/Logger.ts b/adscript/src/utils/Logger.ts index d9858384..0bfc23d8 100644 --- a/adscript/src/utils/Logger.ts +++ b/adscript/src/utils/Logger.ts @@ -1,5 +1,6 @@ import type { Event } from 'theoplayer'; -import { EmbeddedContentMetadata, MainVideoContentMetadata, PlayerState } from '../adscript/AdScript'; +import { PlayerState } from '../adscript/AdScript'; +import { EmbeddedContentMetadata, MainVideoContentMetadata } from '../integration/AdScriptConfiguration'; export class Logger { private readonly debug: boolean; From 0707fbcca3ff7558bcfd1296c655c1838bad4730 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Tue, 23 Jul 2024 15:14:26 +0200 Subject: [PATCH 53/59] Fix loading of AdScript SDK --- adscript/src/integration/LoadAdScriptSDK.ts | 82 +++++++++++---------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/adscript/src/integration/LoadAdScriptSDK.ts b/adscript/src/integration/LoadAdScriptSDK.ts index 0c7dc74a..06eb224b 100644 --- a/adscript/src/integration/LoadAdScriptSDK.ts +++ b/adscript/src/integration/LoadAdScriptSDK.ts @@ -2,50 +2,54 @@ /** * This function loads the AdScript SDK. - * This comes directly from the AdScript documentation: https://adscript.admosphere.cz/en_adScript_browser.html */ export function loadAdScriptSDK(implementationId: string) { - !(function (j, h, m, t, c, z) { - c = c || 'JHMT'; - j[c] = j[c] || []; - j['JHMTApiProtocol'] = 'https:'; - z = z || 3; + loadAdScriptInternal(window, document, implementationId); +} + +/** + * This comes directly from the AdScript documentation: https://adscript.admosphere.cz/en_adScript_browser.html + * It has minimal changes to not use arguments.callee. + */ +function loadAdScriptInternal(j, h, m, t, c, z) { + c = c || 'JHMT'; + j[c] = j[c] || []; + j['JHMTApiProtocol'] = 'https:'; + z = z || 3; - var i = (z % 3) + 1, - a = arguments.callee, - b = h.createElement('script'); + var i = (z % 3) + 1, + b = h.createElement('script'); - (b.async = !0), - b.readyState - ? (b.onreadystatechange = function () { - ('loaded' !== b.readyState && 'complete' !== b.readyState) || - ((b.onreadystataechange = null), j.JHMTApi.init(c, m, t)); - }) - : (b.onload = function () { - j.JHMTApi.init(c, m, t); - }), - (b.src = j['JHMTApiProtocol'] + '//cm' + i + '.jhmt.cz/api.js'), - (b.onerror = function () { + (b.async = !0), + b.readyState + ? (b.onreadystatechange = function () { + ('loaded' !== b.readyState && 'complete' !== b.readyState) || + ((b.onreadystataechange = null), j.JHMTApi.init(c, m, t)); + }) + : (b.onload = function () { + j.JHMTApi.init(c, m, t); + }), + (b.src = j['JHMTApiProtocol'] + '//cm' + i + '.jhmt.cz/api.js'), + (b.onerror = function () { + b.parentNode.removeChild(b); + z++; + i = (z % 3) + 1; + loadAdScriptInternal(j, h, m, t, c, i); + }), + h.getElementsByTagName('head')[0].appendChild(b); + + try { + var it = setInterval(function () { + if (typeof j.JHMTApi !== 'undefined') { + clearInterval(it); + } else { b.parentNode.removeChild(b); z++; i = (z % 3) + 1; - a(j, h, m, t, c, i); - }), - h.getElementsByTagName('head')[0].appendChild(b); - - try { - var it = setInterval(function () { - if (typeof j.JHMTApi !== 'undefined') { - clearInterval(it); - } else { - b.parentNode.removeChild(b); - z++; - i = (z % 3) + 1; - a(j, h, m, t, c, i); - } - }, 1e3); - } catch (e) { - console.log('JHMT: ' + e); - } - })(window, document, implementationId); + loadAdScriptInternal(j, h, m, t, c, i); + } + }, 1e3); + } catch (e) { + console.log('JHMT: ' + e); + } } From b4fbcadb2a8e27d77063e7ca85ed1b7747debe11 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Tue, 23 Jul 2024 15:18:54 +0200 Subject: [PATCH 54/59] Update README --- adscript/README.md | 58 ++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/adscript/README.md b/adscript/README.md index d9971f5e..a7c746ad 100644 --- a/adscript/README.md +++ b/adscript/README.md @@ -32,24 +32,23 @@ First you need to add the AdScript connector to your app : // Define your configuration for the connector: const adScriptConfig = { - // TODO - } - - // Define the metadata for reporting: - const videoMetadata = { - "assetid": "v0000001", - "type": "content", - "program": "Big Buck Bunny", - "title": "Sample Video - Extended", - "length": "635", - "crossId": "000 111 22222", - "livestream": "0", - "channelId": "", - "attribute": "1" + implementationId: 'your-implementation-id', // Replace this! + metadata: { + "assetid": "v0000001", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video - Extended", + "length": "635", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + }, + debug: false } // Create the AdScriptConnector: - const adScriptConnector = new THEOplayerAdScriptConnector.AdScriptConnector(player, adScriptConfig, videoMetadata); + const adScriptConnector = new THEOplayerAdScriptConnector.AdScriptConnector(player, adScriptConfig); ``` @@ -64,24 +63,23 @@ First you need to add the AdScript connector to your app : // Define your configuration for the connector: const adScriptConfig = { - // TODO - } - - // Define the metadata for reporting: - const videoMetadata = { - "assetid": "v0000001", - "type": "content", - "program": "Big Buck Bunny", - "title": "Sample Video - Extended", - "length": "635", - "crossId": "000 111 22222", - "livestream": "0", - "channelId": "", - "attribute": "1" + implementationId: 'your-implementation-id', // Replace this! + metadata: { + "assetid": "v0000001", + "type": "content", + "program": "Big Buck Bunny", + "title": "Sample Video - Extended", + "length": "635", + "crossId": "000 111 22222", + "livestream": "0", + "channelId": "", + "attribute": "1" + }, + debug: false } // Create the AdScriptConnector: - const adScriptConnector = new AdScriptConnector(player, adScriptConfig, videoMetadata); + const adScriptConnector = new AdScriptConnector(player, adScriptConfig); ``` From 2b5319ccfcb0eff454710a07cbcabcc1ac67e7d7 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Tue, 23 Jul 2024 15:19:00 +0200 Subject: [PATCH 55/59] Update sample pages --- adscript/test/pages/main_esm.html | 54 ++++--------------------------- adscript/test/pages/main_umd.html | 53 +++--------------------------- 2 files changed, 11 insertions(+), 96 deletions(-) diff --git a/adscript/test/pages/main_esm.html b/adscript/test/pages/main_esm.html index f33a2a0f..de856e8e 100644 --- a/adscript/test/pages/main_esm.html +++ b/adscript/test/pages/main_esm.html @@ -6,48 +6,7 @@ - - + @@ -90,10 +49,6 @@ let testAssets let adscriptConnector - const adscriptConfig = { - implementationId: "", - debug: true - }; const loadSource = () => { setSourceWithAdScriptMetadata(testAssets[selector.value]) @@ -133,8 +88,11 @@ const adscriptProgramMetadata = jsonResponse[0].metadata adscriptConnector = new AdScriptConnector( player, - adscriptConfig, - adscriptProgramMetadata, + { + implementationId: 'your-implementation-id', + metadata: adscriptProgramMetadata, + debug: true, + } ) populateSourceSelector(jsonResponse) selector.value = 0 diff --git a/adscript/test/pages/main_umd.html b/adscript/test/pages/main_umd.html index c3ba2e54..243c972d 100644 --- a/adscript/test/pages/main_umd.html +++ b/adscript/test/pages/main_umd.html @@ -9,48 +9,6 @@ - -