From f31a81c53dd15549f1fa5bd27f90d5c203453b9a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sat, 29 Jun 2024 23:13:14 +0200 Subject: [PATCH 01/52] prepare integration skeleton --- gemius/.gitignore | 10 ++ gemius/CHANGELOG.md | 7 ++ gemius/README.md | 57 ++++++++++ gemius/package-lock.json | 22 ++++ gemius/package.json | 40 +++++++ gemius/rollup.config.mjs | 15 +++ gemius/src/index.ts | 2 + .../src/integration/GemiusTHEOIntegration.ts | 37 ++++++ gemius/test/pages/main_esm.html | 107 ++++++++++++++++++ gemius/test/pages/main_umd.html | 100 ++++++++++++++++ gemius/tsconfig.json | 11 ++ gemius/typedoc.json | 12 ++ 12 files changed, 420 insertions(+) create mode 100644 gemius/.gitignore create mode 100644 gemius/CHANGELOG.md create mode 100644 gemius/README.md create mode 100644 gemius/package-lock.json create mode 100644 gemius/package.json create mode 100644 gemius/rollup.config.mjs create mode 100644 gemius/src/index.ts create mode 100644 gemius/src/integration/GemiusTHEOIntegration.ts create mode 100644 gemius/test/pages/main_esm.html create mode 100644 gemius/test/pages/main_umd.html create mode 100644 gemius/tsconfig.json create mode 100644 gemius/typedoc.json diff --git a/gemius/.gitignore b/gemius/.gitignore new file mode 100644 index 00000000..92b3d00f --- /dev/null +++ b/gemius/.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/gemius/CHANGELOG.md b/gemius/CHANGELOG.md new file mode 100644 index 00000000..0410e7a4 --- /dev/null +++ b/gemius/CHANGELOG.md @@ -0,0 +1,7 @@ +# @theoplayer/gemius-connector-web + +## 0.0.1 + +### ✨ Features + +- Initial release. diff --git a/gemius/README.md b/gemius/README.md new file mode 100644 index 00000000..ea39bc6e --- /dev/null +++ b/gemius/README.md @@ -0,0 +1,57 @@ +# gemius-connector-web + +The Gemius connector provides a Gemius integration for THEOplayer. + +## Installation + +```sh +npm install @theoplayer/gemius-connector-web +``` + +Load the gplayer.js library from Gemius. There are two options to to this: either you do it synchronously: + +```html + +``` + +... or asynchronously + +```html + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ + + + + + + diff --git a/gemius/test/pages/main_umd.html b/gemius/test/pages/main_umd.html new file mode 100644 index 00000000..4aaae407 --- /dev/null +++ b/gemius/test/pages/main_umd.html @@ -0,0 +1,100 @@ + + + + + Connector test page + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ + + + + + diff --git a/gemius/tsconfig.json b/gemius/tsconfig.json new file mode 100644 index 00000000..d416c1ae --- /dev/null +++ b/gemius/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declarationDir": "dist/types" + }, + "include": [ + "src/**/*" + ] +} diff --git a/gemius/typedoc.json b/gemius/typedoc.json new file mode 100644 index 00000000..7cafc8ff --- /dev/null +++ b/gemius/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": "Gemius Connector" +} From a8bd70150b1ceceb8fead2611c646976de46c521 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sat, 29 Jun 2024 23:13:51 +0200 Subject: [PATCH 02/52] gemius sdk types --- gemius/src/gemius/Gemius.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 gemius/src/gemius/Gemius.d.ts diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts new file mode 100644 index 00000000..6e1bbf44 --- /dev/null +++ b/gemius/src/gemius/Gemius.d.ts @@ -0,0 +1,6 @@ + +export class GemiusPlayer { + constructor(playerID: string, gemiusID: string, additionalParameters: AdditionalParameters); + newProgram(programID: string ,additionalParameters: AdditionalProgramParameters); + +} From 5015db6e6c57b422fecdec5aa9ba40e91d1c4f20 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sat, 29 Jun 2024 23:15:07 +0200 Subject: [PATCH 03/52] copy test source list --- gemius/test/pages/test-assets.json | 107 +++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 gemius/test/pages/test-assets.json diff --git a/gemius/test/pages/test-assets.json b/gemius/test/pages/test-assets.json new file mode 100644 index 00000000..72010fd2 --- /dev/null +++ b/gemius/test/pages/test-assets.json @@ -0,0 +1,107 @@ +[ + { + "label": "VOD (HLS)", + "source": { + "sources": [ + { + "src": "https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8", + "type": "application/x-mpegurl" + } + ] + }, + "metadata": {} + }, + { + "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%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=" + } + ] + }, + "metadata": {} + }, + { + "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%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=" + } + ] + }, + "metadata": {} + }, + { + "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": {} + }, + { + "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": {} + }, + { + "label": "VOD - Google DAI", + "source": { + "sources": [ + { + "type": "application/x-mpegurl", + "ssai": { + "integration": "google-dai", + "availabilityType": "vod", + "contentSourceID": "2528370", + "videoID": "tears-of-steel", + "assetKey": "", + "apiKey": "" + } + } + ] + }, + "metadata": {} + } +] \ No newline at end of file From e30b92bd83a41984a330ec23a1988a74db95bf31 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 13:10:38 +0200 Subject: [PATCH 04/52] additional parameter types --- gemius/src/api/GemiusAdditionalParameters.ts | 110 +++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 gemius/src/api/GemiusAdditionalParameters.ts diff --git a/gemius/src/api/GemiusAdditionalParameters.ts b/gemius/src/api/GemiusAdditionalParameters.ts new file mode 100644 index 00000000..ac21a9bf --- /dev/null +++ b/gemius/src/api/GemiusAdditionalParameters.ts @@ -0,0 +1,110 @@ +export type Resolution = { + width: number; + height: number +} + +export enum ProgramType { + AUDIO = "audio", + VIDEO = "video" +} + +export enum TransmissionType { + ON_DEMAND = 1, + BROADCAST_LIVE_TIMESHIFT = 2 +} + +export enum ProgramGenre { + LIVE = 1, + FILM = 2, + SERIES_VLOG = 3, + PROGRAM = 4, + MUSIC = 5, + TRAILER_TEASER = 6 +} + +export enum AdType { + BREAK = "break", + PROMO = "promo", + SPOT = "spot", + SPONSOR = "sponsor" +} + +export enum AdFormat { + VIDEO = 1, + AUDIO = 2 +} + +export interface PlayerAdditionalParameters { + currentDomain?: string; + volume?: number; + resolution?: Resolution; +} + +export interface NewProgramAdditionalParameters { + programName: string; + programDuration: number; + programType: ProgramType; + transmissionType?: TransmissionType; + transmissionChannel?: string; + transmissionStartTime?: EpochTimeStamp; + programGenre?: ProgramGenre; + programThematicCategory?: string; // TODO check separate document for details + series?: string; + programSeason?: string; + programPartialName?: string; + programProducer?: string; + typology?: string; + premiereDate?: string; + externalPremiereDate?: string; + quality?: Resolution + resolution?: Resolution + volume: number; + customAttributes: any; +} + +export interface NewAdAdditionalParameters { + adName?: string; + adDuration?: number; + adType?: AdType + campaignClassification?: string; + adFormat?: AdFormat; + quality?: Resolution; + resolution?: Resolution; + volume?: number; + customAttributes?: any; +} + +export interface PlayAdEventAdditionalParameters { + autoPlay?: boolean; + adPosition?: number; + breakSize?: number; + resolution?: Resolution; + volume?: number; + adDuration?: number; + customAttributes?: any; +} + +export interface PlayProgramEventAdditionalParameters { + autoPlay?: boolean; + partID?: number; + resolution?: Resolution; + volume?: number; + programDuration?: number; + customAttributes?: any; +} + +export interface PreviousProgramEventAdditionalParameters { + listID?: number +} + +export interface ChangeResolutionEventAddtionalParameters { + resolution?: Resolution; +} + +export interface ChangeVolumeEventAddtionalParameters { + volume?: number; +} + +export interface ChangeQualityEventAddtionalParameters { + quality?: Resolution; +} \ No newline at end of file From d82dc37157c1f539297993d1cb91cbd3551e7449 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 13:10:58 +0200 Subject: [PATCH 05/52] add GemiusConnector API skeleton --- gemius/src/api/GemiusConnector.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 gemius/src/api/GemiusConnector.ts diff --git a/gemius/src/api/GemiusConnector.ts b/gemius/src/api/GemiusConnector.ts new file mode 100644 index 00000000..588d3ecd --- /dev/null +++ b/gemius/src/api/GemiusConnector.ts @@ -0,0 +1,30 @@ +import { ChromelessPlayer } from 'theoplayer'; +import { GemiusTHEOIntegration } from '../integration/GemiusTHEOIntegration'; + + + +export class GemiusConnector { + + private gemiusIntegration: GemiusTHEOIntegration; + + + /** + * Constructor for the THEOplayer Gemius connector + * @param player a THEOplayer instance reference + * @param param1 docs + * @param param2 docs + * @returns + */ + constructor(player: ChromelessPlayer, param1: any, param2: any) { + this.gemiusIntegration = new GemiusTHEOIntegration(player) + } + + + + /** + * Destroy + */ + destroy(): void { + // TODO + } +} \ No newline at end of file From 807a561941919fed41268005b2b85698d007d8ef Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 14:02:23 +0200 Subject: [PATCH 06/52] move to integration folder --- gemius/src/index.ts | 2 +- .../src/{api => integration}/GemiusAdditionalParameters.ts | 0 gemius/src/integration/GemiusConfiguration.ts | 3 +++ gemius/src/{api => integration}/GemiusConnector.ts | 6 +++--- 4 files changed, 7 insertions(+), 4 deletions(-) rename gemius/src/{api => integration}/GemiusAdditionalParameters.ts (100%) create mode 100644 gemius/src/integration/GemiusConfiguration.ts rename gemius/src/{api => integration}/GemiusConnector.ts (66%) diff --git a/gemius/src/index.ts b/gemius/src/index.ts index 7610b4bd..6535afe9 100644 --- a/gemius/src/index.ts +++ b/gemius/src/index.ts @@ -1,2 +1,2 @@ -export { GemiusConnector } from './api/GemiusConnector'; +export { GemiusConnector } from './integration/GemiusConnector'; // export * from './api/path/to/typing/helpers/etc'; diff --git a/gemius/src/api/GemiusAdditionalParameters.ts b/gemius/src/integration/GemiusAdditionalParameters.ts similarity index 100% rename from gemius/src/api/GemiusAdditionalParameters.ts rename to gemius/src/integration/GemiusAdditionalParameters.ts diff --git a/gemius/src/integration/GemiusConfiguration.ts b/gemius/src/integration/GemiusConfiguration.ts new file mode 100644 index 00000000..a1be4d28 --- /dev/null +++ b/gemius/src/integration/GemiusConfiguration.ts @@ -0,0 +1,3 @@ +export interface GemiusConfiguration { + debug?: boolean +} \ No newline at end of file diff --git a/gemius/src/api/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts similarity index 66% rename from gemius/src/api/GemiusConnector.ts rename to gemius/src/integration/GemiusConnector.ts index 588d3ecd..728ac01e 100644 --- a/gemius/src/api/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -1,5 +1,5 @@ import { ChromelessPlayer } from 'theoplayer'; -import { GemiusTHEOIntegration } from '../integration/GemiusTHEOIntegration'; +import { GemiusTHEOIntegration } from './GemiusTHEOIntegration'; @@ -11,11 +11,11 @@ export class GemiusConnector { /** * Constructor for the THEOplayer Gemius connector * @param player a THEOplayer instance reference - * @param param1 docs + * @param configuration a configuration object for the Gemius connector * @param param2 docs * @returns */ - constructor(player: ChromelessPlayer, param1: any, param2: any) { + constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, param2: any) { this.gemiusIntegration = new GemiusTHEOIntegration(player) } From ead639887799baa12d60051729fafae73b5444ce Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 21:30:58 +0200 Subject: [PATCH 07/52] extend types --- gemius/src/gemius/Gemius.d.ts | 56 ++++++++++++++++++- .../integration/GemiusAdditionalParameters.ts | 2 +- gemius/src/integration/GemiusEvents.ts | 21 +++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 gemius/src/integration/GemiusEvents.ts diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts index 6e1bbf44..d044d569 100644 --- a/gemius/src/gemius/Gemius.d.ts +++ b/gemius/src/gemius/Gemius.d.ts @@ -1,6 +1,56 @@ +import { + NewAdAdditionalParameters, + NewProgramAdditionalParameters, + PlayAdEventAdditionalParameters, + PlayProgramEventAdditionalParameters, + PlayerAdditionalParameters, + ListEventAdditionalParameters, + ChangeResolutionEventAddtionalParameters, + ChangeVolumeEventAddtionalParameters, + ChangeQualityEventAddtionalParameters +} from "../integration/GemiusAdditionalParameters"; +import { + PlayEvent, + ListEvent, + ChangeResolutionEvent, + ChangeVolumeEvent, + ChangeQualityEvent, + BreakEvent, + BasicEvent +} from '../integration/GemiusEvents' + export class GemiusPlayer { - constructor(playerID: string, gemiusID: string, additionalParameters: AdditionalParameters); - newProgram(programID: string ,additionalParameters: AdditionalProgramParameters); + constructor(playerID: string, gemiusID: string, additionalParameters?: PlayerAdditionalParameters); + newProgram(programID: string, additionalParameters: NewProgramAdditionalParameters); + newAd(adId: string, additionalParameters?: NewAdAdditionalParameters) + + // Play event + adEvent(programID: string, adID: string, offset: number, event: PlayEvent, additionalParameters: PlayAdEventAdditionalParameters) + programEvent(programID: string, offset: number, event: PlayEvent, additionalParameters: PlayProgramEventAdditionalParameters) + + // List event + programEvent(programID: string, offset: number, event: ListEvent, additionalParameters?: ListEventAdditionalParameters) + + // Change resolution events + programEvent(programID: string, offset: number, event: ChangeResolutionEvent, additionalParameters?: ChangeResolutionEventAddtionalParameters) + adEvent(programID: string, offset: number, event: ChangeResolutionEvent, additionalParameters?: ChangeResolutionEventAddtionalParameters) + + // Change volume events + programEvent(programID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) + adEvent(programID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) + + // Change quality events + programEvent(programID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) + adEvent(programID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) + + // Break event (program only) + programEvent(programID: string, offset: number, event: BreakEvent) + + // Basic events for both program and ads that don't require additional parameters + adEvent(programID: string, adID: string, offset: number, event: BasicEvent) + programEvent(programID: string, offset: number, event: BasicEvent) + + -} +} \ No newline at end of file diff --git a/gemius/src/integration/GemiusAdditionalParameters.ts b/gemius/src/integration/GemiusAdditionalParameters.ts index ac21a9bf..eb04351f 100644 --- a/gemius/src/integration/GemiusAdditionalParameters.ts +++ b/gemius/src/integration/GemiusAdditionalParameters.ts @@ -93,7 +93,7 @@ export interface PlayProgramEventAdditionalParameters { customAttributes?: any; } -export interface PreviousProgramEventAdditionalParameters { +export interface ListEventAdditionalParameters { listID?: number } diff --git a/gemius/src/integration/GemiusEvents.ts b/gemius/src/integration/GemiusEvents.ts new file mode 100644 index 00000000..a392cf41 --- /dev/null +++ b/gemius/src/integration/GemiusEvents.ts @@ -0,0 +1,21 @@ +export type PlayEvent = "play" +export type BreakEvent = "break" +export type ChangeResolutionEvent = "chngRes" +export type ChangeVolumeEvent = "chngVol" +export type ChangeQualityEvent = "chngQual" + +export enum ListEvent { + NEXT = "next", + PREVIOUS = "prev" +} + +export enum BasicEvent { + STOP = "stop", + PAUSE = "pause", + BUFFER = "buffer", + SEEK = "seek", + COMPLETE = "complete", + CLOSE = "close", + SKIP = "skip", + NEXT = "next" +} \ No newline at end of file From cdc387aac7f5f0106c052021219b121f7be94b1d Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 21:31:42 +0200 Subject: [PATCH 08/52] introduce basic connector configuration object --- gemius/src/integration/GemiusConfiguration.ts | 3 ++- gemius/src/integration/GemiusConnector.ts | 6 ++---- gemius/src/integration/GemiusTHEOIntegration.ts | 11 ++++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/gemius/src/integration/GemiusConfiguration.ts b/gemius/src/integration/GemiusConfiguration.ts index a1be4d28..61bd8263 100644 --- a/gemius/src/integration/GemiusConfiguration.ts +++ b/gemius/src/integration/GemiusConfiguration.ts @@ -1,3 +1,4 @@ export interface GemiusConfiguration { - debug?: boolean + gemiusID: string; + debug?: boolean; } \ No newline at end of file diff --git a/gemius/src/integration/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts index 728ac01e..7e04665d 100644 --- a/gemius/src/integration/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -1,13 +1,11 @@ import { ChromelessPlayer } from 'theoplayer'; import { GemiusTHEOIntegration } from './GemiusTHEOIntegration'; - - +import { GemiusConfiguration } from './GemiusConfiguration'; export class GemiusConnector { private gemiusIntegration: GemiusTHEOIntegration; - /** * Constructor for the THEOplayer Gemius connector * @param player a THEOplayer instance reference @@ -16,7 +14,7 @@ export class GemiusConnector { * @returns */ constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, param2: any) { - this.gemiusIntegration = new GemiusTHEOIntegration(player) + this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration) } diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index ec9eeb21..a38d5c64 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -3,16 +3,21 @@ import { SourceChangeEvent, } from 'theoplayer'; import { GemiusPlayer } from '../gemius/Gemius'; +import { GemiusConfiguration } from './GemiusConfiguration'; + const LOG_THEOPLAYER_EVENTS = true; +const THEOPLAYER_ID = "THEOplayer" export class GemiusTHEOIntegration { // References for constructor arguments private player: ChromelessPlayer; + private debug: boolean; private gemiusPlayer: GemiusPlayer; - constructor(player: ChromelessPlayer) { + constructor(player: ChromelessPlayer, configuration: GemiusConfiguration) { this.player = player; - this.gemiusPlayer = new GemiusPlayer('THEOplayer','12345', {}) + this.debug = configuration.debug ?? false; + this.gemiusPlayer = new GemiusPlayer(THEOPLAYER_ID ,configuration.gemiusID, {}); this.addListeners(); } @@ -30,7 +35,7 @@ export class GemiusTHEOIntegration { // EVENT HANDLERS private onSourceChange = (event: SourceChangeEvent) => { - if (LOG_THEOPLAYER_EVENTS) + if (this.debug && LOG_THEOPLAYER_EVENTS) console.log(`[COMSCORE - THEOplayer EVENTS] ${event.type} event`); this.gemiusPlayer.newProgram('modern family', {}) }; From 261c7e0420dcd625564e284b21ecaafb652d00bb Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 22:20:47 +0200 Subject: [PATCH 09/52] export GemiusConfiguration --- gemius/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gemius/src/index.ts b/gemius/src/index.ts index 6535afe9..e54b95bf 100644 --- a/gemius/src/index.ts +++ b/gemius/src/index.ts @@ -1,2 +1,3 @@ export { GemiusConnector } from './integration/GemiusConnector'; +export * from './integration/GemiusConfiguration' // export * from './api/path/to/typing/helpers/etc'; From 7b65b2345ae466d0c9c10d6eab83f6bc90e8bc05 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Sun, 30 Jun 2024 22:21:09 +0200 Subject: [PATCH 10/52] make volume and customattr optional --- gemius/src/integration/GemiusAdditionalParameters.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gemius/src/integration/GemiusAdditionalParameters.ts b/gemius/src/integration/GemiusAdditionalParameters.ts index eb04351f..d4c9f56d 100644 --- a/gemius/src/integration/GemiusAdditionalParameters.ts +++ b/gemius/src/integration/GemiusAdditionalParameters.ts @@ -58,8 +58,8 @@ export interface NewProgramAdditionalParameters { externalPremiereDate?: string; quality?: Resolution resolution?: Resolution - volume: number; - customAttributes: any; + volume?: number; + customAttributes?: any; } export interface NewAdAdditionalParameters { From 9b15c95a181434b4d5d259f55c69ecf6abc956b1 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 11:20:44 +0200 Subject: [PATCH 11/52] include public parameter interfaces --- ...ionalParameters.ts => GemiusParameters.ts} | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) rename gemius/src/integration/{GemiusAdditionalParameters.ts => GemiusParameters.ts} (86%) diff --git a/gemius/src/integration/GemiusAdditionalParameters.ts b/gemius/src/integration/GemiusParameters.ts similarity index 86% rename from gemius/src/integration/GemiusAdditionalParameters.ts rename to gemius/src/integration/GemiusParameters.ts index d4c9f56d..4229d682 100644 --- a/gemius/src/integration/GemiusAdditionalParameters.ts +++ b/gemius/src/integration/GemiusParameters.ts @@ -59,7 +59,9 @@ export interface NewProgramAdditionalParameters { quality?: Resolution resolution?: Resolution volume?: number; - customAttributes?: any; + customAttributes?: { + [key: string]: string; + }; } export interface NewAdAdditionalParameters { @@ -71,7 +73,9 @@ export interface NewAdAdditionalParameters { quality?: Resolution; resolution?: Resolution; volume?: number; - customAttributes?: any; + customAttributes?: { + [key: string]: string; + } } export interface PlayAdEventAdditionalParameters { @@ -81,7 +85,9 @@ export interface PlayAdEventAdditionalParameters { resolution?: Resolution; volume?: number; adDuration?: number; - customAttributes?: any; + customAttributes?: { + [key: string]: string; + } } export interface PlayProgramEventAdditionalParameters { @@ -90,7 +96,9 @@ export interface PlayProgramEventAdditionalParameters { resolution?: Resolution; volume?: number; programDuration?: number; - customAttributes?: any; + customAttributes?: { + [key: string]: string; + } } export interface ListEventAdditionalParameters { @@ -107,4 +115,8 @@ export interface ChangeVolumeEventAddtionalParameters { export interface ChangeQualityEventAddtionalParameters { quality?: Resolution; +} + +export interface GemiusProgramParameters extends NewProgramAdditionalParameters { + programID: string; } \ No newline at end of file From c1a829a74bc6b8d5007e00f7da2697c0a72f4349 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 11:21:09 +0200 Subject: [PATCH 12/52] add destroy method --- gemius/src/integration/GemiusConnector.ts | 3 +-- gemius/src/integration/GemiusTHEOIntegration.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gemius/src/integration/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts index 7e04665d..01f2e148 100644 --- a/gemius/src/integration/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -18,11 +18,10 @@ export class GemiusConnector { } - /** * Destroy */ destroy(): void { - // TODO + this.gemiusIntegration.destroy() } } \ No newline at end of file diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index a38d5c64..520fbd6e 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -23,6 +23,7 @@ export class GemiusTHEOIntegration { public destroy() { this.removeListeners(); + this.gemiusPlayer.dispose(); } private addListeners(): void { From 4953ad9306e498ae29709a39d9dfe4123e3eeee5 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 11:21:22 +0200 Subject: [PATCH 13/52] update types --- gemius/src/gemius/Gemius.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts index d044d569..073cdd56 100644 --- a/gemius/src/gemius/Gemius.d.ts +++ b/gemius/src/gemius/Gemius.d.ts @@ -8,7 +8,7 @@ import { ChangeResolutionEventAddtionalParameters, ChangeVolumeEventAddtionalParameters, ChangeQualityEventAddtionalParameters -} from "../integration/GemiusAdditionalParameters"; +} from "../integration/GemiusParameters"; import { PlayEvent, ListEvent, @@ -50,6 +50,8 @@ export class GemiusPlayer { // Basic events for both program and ads that don't require additional parameters adEvent(programID: string, adID: string, offset: number, event: BasicEvent) programEvent(programID: string, offset: number, event: BasicEvent) + + dispose(); From feef5ff2d96ca5d9f1417416fe9c81e4f32b0d39 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 12:34:03 +0200 Subject: [PATCH 14/52] store program parameters --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 520fbd6e..b4b51146 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -4,6 +4,7 @@ import { } from 'theoplayer'; import { GemiusPlayer } from '../gemius/Gemius'; import { GemiusConfiguration } from './GemiusConfiguration'; +import { GemiusProgramParameters } from './GemiusParameters'; const LOG_THEOPLAYER_EVENTS = true; const THEOPLAYER_ID = "THEOplayer" @@ -13,6 +14,7 @@ export class GemiusTHEOIntegration { private player: ChromelessPlayer; private debug: boolean; private gemiusPlayer: GemiusPlayer; + private programParameters: GemiusProgramParameters | undefined; constructor(player: ChromelessPlayer, configuration: GemiusConfiguration) { this.player = player; From a8a962d2f71e0d58700c66cfd7951f1d5df43fee Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 17:42:34 +0200 Subject: [PATCH 15/52] basic event logs --- gemius/src/utils/Logger.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 gemius/src/utils/Logger.ts diff --git a/gemius/src/utils/Logger.ts b/gemius/src/utils/Logger.ts new file mode 100644 index 00000000..37448671 --- /dev/null +++ b/gemius/src/utils/Logger.ts @@ -0,0 +1,10 @@ +import { Event } from "theoplayer"; + +const LOG_THEOPLAYER_EVENTS = true; + +export class Logger { + static log = (event: Event) => { + if (LOG_THEOPLAYER_EVENTS) + console.log(`[GEMIUS - THEOplayer EVENTS] ${event.type} event`); + } +} \ No newline at end of file From ebfdc01adc0a372dc913500119df04b028c99484 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 17:43:30 +0200 Subject: [PATCH 16/52] pass program parameters to integration --- gemius/src/integration/GemiusConnector.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gemius/src/integration/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts index 01f2e148..7cc46190 100644 --- a/gemius/src/integration/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -1,6 +1,7 @@ import { ChromelessPlayer } from 'theoplayer'; import { GemiusTHEOIntegration } from './GemiusTHEOIntegration'; import { GemiusConfiguration } from './GemiusConfiguration'; +import { GemiusProgramParameters } from './GemiusParameters'; export class GemiusConnector { @@ -10,11 +11,11 @@ export class GemiusConnector { * Constructor for the THEOplayer Gemius connector * @param player a THEOplayer instance reference * @param configuration a configuration object for the Gemius connector - * @param param2 docs + * @param programParameters the parameters associated with the first source that will be set to the player * @returns */ - constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, param2: any) { - this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration) + constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { + this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration, programParameters) } From 2a8149989a52b25b22ac30462d01698344f3fa7a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 17:43:55 +0200 Subject: [PATCH 17/52] report play pause and buffer events --- .../src/integration/GemiusTHEOIntegration.ts | 102 ++++++++++++++++-- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index b4b51146..97e8d45b 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -1,25 +1,39 @@ import { + Ad, + AdBreakEvent, ChromelessPlayer, + PauseEvent, + PlayEvent, SourceChangeEvent, + WaitingEvent, } from 'theoplayer'; import { GemiusPlayer } from '../gemius/Gemius'; import { GemiusConfiguration } from './GemiusConfiguration'; import { GemiusProgramParameters } from './GemiusParameters'; +import { Logger } from '../utils/Logger'; +import { BasicEvent } from './GemiusEvents'; -const LOG_THEOPLAYER_EVENTS = true; const THEOPLAYER_ID = "THEOplayer" +const DEFAULT_AD_ID = "PLACEHOLDER ID" + export class GemiusTHEOIntegration { // References for constructor arguments private player: ChromelessPlayer; private debug: boolean; private gemiusPlayer: GemiusPlayer; - private programParameters: GemiusProgramParameters | undefined; + private programParameters: GemiusProgramParameters; + + private partCount: number = 1; + private adCount: number = 1; + private inAd: boolean = false; + private currentAd: Ad | undefined; - constructor(player: ChromelessPlayer, configuration: GemiusConfiguration) { + constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { this.player = player; this.debug = configuration.debug ?? false; this.gemiusPlayer = new GemiusPlayer(THEOPLAYER_ID ,configuration.gemiusID, {}); + this.programParameters = programParameters; this.addListeners(); } @@ -30,16 +44,92 @@ export class GemiusTHEOIntegration { private addListeners(): void { this.player.addEventListener('sourcechange', this.onSourceChange); + this.player.addEventListener('play', this.onPlay); + this.player.addEventListener('pause', this.onPause); + if (this.player.ads) { + this.player.ads.addEventListener('adbreakbegin', this.onAdBreakBegin) + } } private removeListeners(): void { this.player.removeEventListener('sourcechange', this.onSourceChange); + this.player.removeEventListener('play', this.onPlay); + this.player.removeEventListener('pause', this.onPause); + if (this.player.ads) { + this.player.ads.removeEventListener('adbreakbegin', this.onAdBreakBegin) + } } // EVENT HANDLERS private onSourceChange = (event: SourceChangeEvent) => { - if (this.debug && LOG_THEOPLAYER_EVENTS) - console.log(`[COMSCORE - THEOplayer EVENTS] ${event.type} event`); - this.gemiusPlayer.newProgram('modern family', {}) + Logger.log(event); + if (!this.programParameters) { + console.log(`[GEMIUS] No program parameters were provdided`); + return; + } + if (!event.source) { + // TODO handle some clear source flow + return; + } + this.partCount = 1; + this.currentAd = undefined; + + const { programID, customAttributes, ...additionalParameters } = this.programParameters + this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) }; + + private onPlay = (event: PlayEvent) => { + Logger.log(event); + const { programID } = this.programParameters; + const computedVolume = this.player.muted ? -1 : (this.player.volume * 100) + if (this.currentAd) { + const { id, adBreak, duration } = this.currentAd; + const { timeOffset, ads } = adBreak + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, "play", { + autoPlay: true, + adPosition: this.adCount, + breakSize: ads?.length, + // resolution: `AxB`, TODO + volume: computedVolume, + adDuration: duration + }) + } else { + this.gemiusPlayer.programEvent(programID, this.player.currentTime, "play", { + autoPlay: this.player.autoplay, + partID: this.partCount, + // resolution: `AxB`; TODO + volume: computedVolume, + programDuration: this.player.duration + }) + } + } + + private onPause = (event: PauseEvent) => { + Logger.log(event); + this.reportBasicEvent(BasicEvent.PAUSE) + } + + private onWaiting = (event: WaitingEvent) => { + Logger.log(event); + this.reportBasicEvent(BasicEvent.BUFFER) + } + + private onAdBreakBegin = (event: AdBreakEvent<'adbreakbegin'>) => { + Logger.log(event); + const { programID } = this.programParameters + const { adBreak } = event + this.gemiusPlayer.programEvent(programID, adBreak.timeOffset, "break") + } + + private reportBasicEvent = (event: BasicEvent) => { + const { programID } = this.programParameters; + const { currentTime } = this.player; + if (this.currentAd) { + const { id, adBreak } = this.currentAd; + const { timeOffset } = adBreak + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset + currentTime, event); // TODO make SSAI ready + } else { + this.gemiusPlayer.programEvent(programID,currentTime, event) + } + } } From ff340c68c0561978e33ebbefe1566f37e264a210 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 23:53:11 +0200 Subject: [PATCH 18/52] correct mistake in gemius types --- gemius/src/gemius/Gemius.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts index 073cdd56..0dd2e631 100644 --- a/gemius/src/gemius/Gemius.d.ts +++ b/gemius/src/gemius/Gemius.d.ts @@ -24,10 +24,6 @@ export class GemiusPlayer { constructor(playerID: string, gemiusID: string, additionalParameters?: PlayerAdditionalParameters); newProgram(programID: string, additionalParameters: NewProgramAdditionalParameters); newAd(adId: string, additionalParameters?: NewAdAdditionalParameters) - - // Play event - adEvent(programID: string, adID: string, offset: number, event: PlayEvent, additionalParameters: PlayAdEventAdditionalParameters) - programEvent(programID: string, offset: number, event: PlayEvent, additionalParameters: PlayProgramEventAdditionalParameters) // List event programEvent(programID: string, offset: number, event: ListEvent, additionalParameters?: ListEventAdditionalParameters) @@ -38,11 +34,15 @@ export class GemiusPlayer { // Change volume events programEvent(programID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) - adEvent(programID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) + adEvent(programID: string, adID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) // Change quality events programEvent(programID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) - adEvent(programID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) + adEvent(programID: string, adID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) + + // Play event + adEvent(programID: string, adID: string, offset: number, event: PlayEvent, additionalParameters: PlayAdEventAdditionalParameters) + programEvent(programID: string, offset: number, event: PlayEvent, additionalParameters: PlayProgramEventAdditionalParameters) // Break event (program only) programEvent(programID: string, offset: number, event: BreakEvent) From c2f0aef770d9904e8383114a8a4073d4006b3878 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 23:53:30 +0200 Subject: [PATCH 19/52] change resolution type to string --- gemius/src/integration/GemiusParameters.ts | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/gemius/src/integration/GemiusParameters.ts b/gemius/src/integration/GemiusParameters.ts index 4229d682..4289a0e5 100644 --- a/gemius/src/integration/GemiusParameters.ts +++ b/gemius/src/integration/GemiusParameters.ts @@ -1,8 +1,3 @@ -export type Resolution = { - width: number; - height: number -} - export enum ProgramType { AUDIO = "audio", VIDEO = "video" @@ -37,7 +32,7 @@ export enum AdFormat { export interface PlayerAdditionalParameters { currentDomain?: string; volume?: number; - resolution?: Resolution; + resolution?: string; } export interface NewProgramAdditionalParameters { @@ -56,8 +51,8 @@ export interface NewProgramAdditionalParameters { typology?: string; premiereDate?: string; externalPremiereDate?: string; - quality?: Resolution - resolution?: Resolution + quality?: string + resolution?: string volume?: number; customAttributes?: { [key: string]: string; @@ -70,8 +65,8 @@ export interface NewAdAdditionalParameters { adType?: AdType campaignClassification?: string; adFormat?: AdFormat; - quality?: Resolution; - resolution?: Resolution; + quality?: string; + resolution?: string; volume?: number; customAttributes?: { [key: string]: string; @@ -82,7 +77,7 @@ export interface PlayAdEventAdditionalParameters { autoPlay?: boolean; adPosition?: number; breakSize?: number; - resolution?: Resolution; + resolution?: string; volume?: number; adDuration?: number; customAttributes?: { @@ -93,7 +88,7 @@ export interface PlayAdEventAdditionalParameters { export interface PlayProgramEventAdditionalParameters { autoPlay?: boolean; partID?: number; - resolution?: Resolution; + resolution?: string; volume?: number; programDuration?: number; customAttributes?: { @@ -106,7 +101,7 @@ export interface ListEventAdditionalParameters { } export interface ChangeResolutionEventAddtionalParameters { - resolution?: Resolution; + resolution?: string; } export interface ChangeVolumeEventAddtionalParameters { @@ -114,7 +109,7 @@ export interface ChangeVolumeEventAddtionalParameters { } export interface ChangeQualityEventAddtionalParameters { - quality?: Resolution; + quality?: string; } export interface GemiusProgramParameters extends NewProgramAdditionalParameters { From 1eda94e578537219aaff5f156517fdef5d0c9b13 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Mon, 1 Jul 2024 23:55:12 +0200 Subject: [PATCH 20/52] report buffer, seek, complete, close, chngQual, chngVol --- .../src/integration/GemiusTHEOIntegration.ts | 113 +++++++++++++++++- 1 file changed, 110 insertions(+), 3 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 97e8d45b..37326089 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -1,10 +1,20 @@ import { Ad, AdBreakEvent, + AdEvent, + AdSkipEvent, + AddTrackEvent, ChromelessPlayer, + EndedEvent, + MediaTrack, PauseEvent, PlayEvent, + QualityEvent, + RemoveTrackEvent, + SeekingEvent, SourceChangeEvent, + VideoQuality, + VolumeChangeEvent, WaitingEvent, } from 'theoplayer'; import { GemiusPlayer } from '../gemius/Gemius'; @@ -26,7 +36,6 @@ export class GemiusTHEOIntegration { private partCount: number = 1; private adCount: number = 1; - private inAd: boolean = false; private currentAd: Ad | undefined; constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { @@ -46,8 +55,18 @@ export class GemiusTHEOIntegration { this.player.addEventListener('sourcechange', this.onSourceChange); this.player.addEventListener('play', this.onPlay); this.player.addEventListener('pause', this.onPause); + this.player.addEventListener('waiting', this.onWaiting); + this.player.addEventListener('seeking', this.onSeeking); + this.player.addEventListener('ended', this.onEnded); + this.player.addEventListener('volumechange', this.onVolumeChange); + this.player.videoTracks.addEventListener('addtrack', this.onAddTrack); + this.player.videoTracks.addEventListener('removetrack', this.onRemoveTrack); if (this.player.ads) { this.player.ads.addEventListener('adbreakbegin', this.onAdBreakBegin) + this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd) + this.player.ads.addEventListener('adbegin', this.onAdBegin) + this.player.ads.addEventListener('adend', this.onAdEnd) + this.player.ads.addEventListener('adskip', this.onAdSkip) } } @@ -55,8 +74,19 @@ export class GemiusTHEOIntegration { this.player.removeEventListener('sourcechange', this.onSourceChange); this.player.removeEventListener('play', this.onPlay); this.player.removeEventListener('pause', this.onPause); + this.player.removeEventListener('waiting', this.onWaiting); + this.player.removeEventListener('seeking', this.onSeeking); + this.player.removeEventListener('ended', this.onEnded); + this.player.removeEventListener('volumechange', this.onVolumeChange); + this.player.videoTracks.removeEventListener('addtrack', this.onAddTrack); + this.player.videoTracks.removeEventListener('removetrack', this.onRemoveTrack); if (this.player.ads) { this.player.ads.removeEventListener('adbreakbegin', this.onAdBreakBegin) + this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd) + this.player.ads.removeEventListener('adbegin', this.onAdBegin) + this.player.ads.removeEventListener('adend', this.onAdEnd) + this.player.ads.removeEventListener('adskip', this.onAdSkip) + } } @@ -69,8 +99,10 @@ export class GemiusTHEOIntegration { } if (!event.source) { // TODO handle some clear source flow + this.reportBasicEvent(BasicEvent.CLOSE) return; } + this.reportBasicEvent(BasicEvent.CLOSE) this.partCount = 1; this.currentAd = undefined; @@ -114,20 +146,95 @@ export class GemiusTHEOIntegration { this.reportBasicEvent(BasicEvent.BUFFER) } + private onSeeking = (event: SeekingEvent) => { + Logger.log(event); + this.reportBasicEvent(BasicEvent.SEEK) + } + + private onEnded = (event: EndedEvent) => { + Logger.log(event); + this.reportBasicEvent(BasicEvent.COMPLETE) + } + + private onVolumeChange = (event: VolumeChangeEvent) => { + Logger.log(event); + const { volume } = event + const { programID } = this.programParameters + const computedVolume = this.player.muted ? -1 : (volume * 100) + if (this.currentAd) { + const { id, adBreak } = this.currentAd; + const { timeOffset } = adBreak + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, "chngVol", { volume: computedVolume }); // TODO make SSAI ready + } else { + const { currentTime } = this.player + this.gemiusPlayer.programEvent(programID, currentTime, "chngVol", { volume: computedVolume}) + } + } + + private onAddTrack = (event: AddTrackEvent) => { + const videoTrack = event.track as MediaTrack; + videoTrack.addEventListener('activequalitychanged', this.onActiveQualityChanged) + } + + private onRemoveTrack = (event: RemoveTrackEvent) => { + const videoTrack = event.track as MediaTrack; + videoTrack.removeEventListener('activequalitychanged',this.onActiveQualityChanged) + } + + private onActiveQualityChanged = (event: QualityEvent<"activequalitychanged">) => { + const { quality } = event; + const videoQuality = quality as VideoQuality + const { width, height } = videoQuality + const { programID } = this.programParameters + const { currentTime } = this.player + this.gemiusPlayer.programEvent(programID, currentTime, "chngQual", { quality: `${width}x${height}` }); + + } + private onAdBreakBegin = (event: AdBreakEvent<'adbreakbegin'>) => { Logger.log(event); const { programID } = this.programParameters const { adBreak } = event - this.gemiusPlayer.programEvent(programID, adBreak.timeOffset, "break") + this.gemiusPlayer.programEvent(programID, adBreak.timeOffset, "break"); + } + + private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { + Logger.log(event); + this.partCount++ + this.adCount = 1; + } + + private onAdBegin = (event: AdEvent<'adbegin'>) => { + Logger.log(event); + const { ad } = event; + this.currentAd = ad + } + + + private onAdEnd = (event: AdEvent<'adend'>) => { + Logger.log(event); + const { programID } = this.programParameters + const { ad } = event + this.gemiusPlayer.programEvent(programID, ad.adBreak.timeOffset, BasicEvent.COMPLETE); + this.adCount++ + this.currentAd = undefined; } + private onAdSkip = (event: AdSkipEvent) => { + Logger.log(event); + const { programID } = this.programParameters + const { ad } = event + this.gemiusPlayer.programEvent(programID, ad.adBreak.timeOffset, BasicEvent.SKIP); + } + + private reportBasicEvent = (event: BasicEvent) => { const { programID } = this.programParameters; const { currentTime } = this.player; if (this.currentAd) { const { id, adBreak } = this.currentAd; const { timeOffset } = adBreak - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset + currentTime, event); // TODO make SSAI ready + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, event); // TODO make SSAI ready } else { this.gemiusPlayer.programEvent(programID,currentTime, event) } From 6f85caea4bae9acbf097385977bd20c6245a9c9a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 2 Jul 2024 23:15:00 +0200 Subject: [PATCH 21/52] log qualitychanges --- gemius/src/integration/GemiusTHEOIntegration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 37326089..fc1cd17d 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -182,6 +182,7 @@ export class GemiusTHEOIntegration { } private onActiveQualityChanged = (event: QualityEvent<"activequalitychanged">) => { + Logger.log(event) const { quality } = event; const videoQuality = quality as VideoQuality const { width, height } = videoQuality From 7e0128e7133607bdd9071fe0acd11eb28de0de1a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 2 Jul 2024 23:15:14 +0200 Subject: [PATCH 22/52] declare GemiusPlayer in global scope --- gemius/src/gemius/Gemius.d.ts | 10 +++++++--- gemius/src/integration/GemiusTHEOIntegration.ts | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts index 0dd2e631..eba8115e 100644 --- a/gemius/src/gemius/Gemius.d.ts +++ b/gemius/src/gemius/Gemius.d.ts @@ -19,6 +19,13 @@ import { BasicEvent } from '../integration/GemiusEvents' +declare global { + interface Window { + GemiusPlayer: typeof GemiusPlayer; + } + } + + export class GemiusPlayer { constructor(playerID: string, gemiusID: string, additionalParameters?: PlayerAdditionalParameters); @@ -52,7 +59,4 @@ export class GemiusPlayer { programEvent(programID: string, offset: number, event: BasicEvent) dispose(); - - - } \ No newline at end of file diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index fc1cd17d..d2aacd42 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -17,7 +17,7 @@ import { VolumeChangeEvent, WaitingEvent, } from 'theoplayer'; -import { GemiusPlayer } from '../gemius/Gemius'; +import type { GemiusPlayer } from '../gemius/Gemius'; import { GemiusConfiguration } from './GemiusConfiguration'; import { GemiusProgramParameters } from './GemiusParameters'; import { Logger } from '../utils/Logger'; @@ -41,7 +41,7 @@ export class GemiusTHEOIntegration { constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { this.player = player; this.debug = configuration.debug ?? false; - this.gemiusPlayer = new GemiusPlayer(THEOPLAYER_ID ,configuration.gemiusID, {}); + this.gemiusPlayer = new window.GemiusPlayer(THEOPLAYER_ID ,configuration.gemiusID, {}); this.programParameters = programParameters; this.addListeners(); } From 330012bc4da06fbdadb67fec528da687cd575cb3 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 16 Jul 2024 23:18:56 +0200 Subject: [PATCH 23/52] include update method for program parameters --- gemius/src/integration/GemiusConnector.ts | 4 + .../src/integration/GemiusTHEOIntegration.ts | 4 + gemius/test/pages/gplayer.js | 680 ++++++++++++++++++ gemius/test/pages/main_esm.html | 18 +- gemius/test/pages/main_umd.html | 17 +- gemius/test/pages/preroll-empty.xml | 1 + 6 files changed, 710 insertions(+), 14 deletions(-) create mode 100644 gemius/test/pages/gplayer.js create mode 100644 gemius/test/pages/preroll-empty.xml diff --git a/gemius/src/integration/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts index 7cc46190..57512172 100644 --- a/gemius/src/integration/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -18,6 +18,10 @@ export class GemiusConnector { this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration, programParameters) } + update(programParameters: GemiusProgramParameters) { + this.gemiusIntegration.update(programParameters) + } + /** * Destroy diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index d2aacd42..e83e439d 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -46,6 +46,10 @@ export class GemiusTHEOIntegration { this.addListeners(); } + public update(programParameters: GemiusProgramParameters) { + this.programParameters = programParameters; + } + public destroy() { this.removeListeners(); this.gemiusPlayer.dispose(); diff --git a/gemius/test/pages/gplayer.js b/gemius/test/pages/gplayer.js new file mode 100644 index 00000000..21e55e10 --- /dev/null +++ b/gemius/test/pages/gplayer.js @@ -0,0 +1,680 @@ +// (c) by Gemius SA - gemius player tools +// ver. 2.12 + +// gemius_pending.js +function gemius_pending(i) { window[i] = window[i] || function() {var x = window[i+'_pdata'] = window[i+'_pdata'] || []; x[x.length]=Array.prototype.slice.call(arguments, 0);};}; +(function(cmds) { var c; while(c = cmds.pop()) gemius_pending(c)})(['gemius_cmd', 'gemius_hit', 'gemius_event', 'gemius_init', 'pp_gemius_hit', 'pp_gemius_event', 'pp_gemius_init']); +window.pp_gemius_cmd = window.pp_gemius_cmd || window.gemius_cmd; + +if (typeof GemiusPlayerVisibility == "undefined") { + var GemiusPlayerVisibility = { + isframe : null, + framevis : null, + childs : [], + timerID : null, + init : function() { + try { + GemiusPlayerVisibility.isframe = (top !== self); + if (window.addEventListener) { + window.addEventListener("message", GemiusPlayerVisibility._msgreceive, false); + } else if (window.attachEvent) { + window.attachEvent("onmessage", GemiusPlayerVisibility._msgreceive); + } + + if (GemiusPlayerVisibility.isframe) { + parent.postMessage("__xx_gplayer_vischeck_xx__","*"); + } + } catch (e) { + } + }, + check : function(object) { + try { + if (GemiusPlayerVisibility.isframe && GemiusPlayerVisibility.framevis===null) { + parent.postMessage("__xx_gplayer_vischeck_xx__","*"); + return null; + } else if (GemiusPlayerVisibility.isframe && GemiusPlayerVisibility.framevis===false) { + return false; + } else if (GemiusPlayerVisibility.isframe !== null) { + var vis = GemiusPlayerVisibility._inScreen(object); + return vis; + } else { + return null; + } + } catch (e) { + return null; + } + }, + _msgreceive : function(e) { + if (typeof e.data=="string" && e.data=="__xx_gplayer_vischeck_xx__") { + try { + if (GemiusPlayerVisibility.isframe && GemiusPlayerVisibility.framevis===null) { + parent.postMessage("__xx_gplayer_vischeck_xx__","*"); + } + var frames = document.getElementsByTagName('iframe'); + var frame = null; + try { + for (var i = 0; i0 && visy>0 && (visx*visy > rect.height*rect.width*0.5 || visx*visy > window.innerHeight*window.innerWidth*0.5); + return vis; + } + } + }, + _isChild : function(p, c) { + var node = c.parentNode; + while (node != null) { + if (node == p) { + return true; + } + node = node.parentNode; + } + return false; + } + } + + GemiusPlayerVisibility.init(); +} + +function GemiusPlayer(playerID, gemiusID, playerData) { + this.interval = 5 * 60; + this.updateInterval = 1; + this.instanceID = (((new Date()).getTime()) + Math.floor(Math.random()*1000)).toString(); + this.playerID = playerID; + this.gemiusID = gemiusID; + this.playerData = (playerData || {}); + this.initialized = false; + this.disposed = false; + this.programs = {}; + this.ads = {}; + this.hitsCounter = 0; + this.currentProgramID = null; + this.videoObject = null; + this.resolution = null; + this.visible = null; + this.hidetime = null; + this.continueIntervalID = null; + this.updateIntervalID = null; + this.unloadFun = null; + this.pagehideFun = null; + this.pageshowFun = null; + + this._playerDataKeys = {"currentDomain":"_SPD", "resolution":"_SPR", "volume":"_SPV"}; + this._programDataKeys = {'programType':'_SCTE','programDuration':'_SCD','programTransmission':'_SCTR','programName':'_SCT', + 'series':'_SCS','typology':'_SCTY','premiereDate':'_SCPD','externalPremiereDate':'_SCEPD','quality':'_SCQ', + 'resolution':'_SCR', 'volume':'_SCV', 'programGenre':'_SCG','programPartialName':'_SCPN','programProducer':'_SCPP', + 'programThematicCategory':'_SCTC','programSeason':'_SCSS','transmissionChannel':'_SCTB','transmissionStartTime':'_SCTS', + 'transmissionType':'_SCTT'}; + this._programExtraDataKeys = {'partID':'_SCP'}; + this._adDataKeys = {'adName':'_SAN','adDuration':'_SAD','adTransmission':'_SATR','adType':'_SAT','campaignClassification':'_SAC', + 'quality':'_SAQ', 'resolution':'_SAR', 'volume':'_SAV', 'adFormat':'_SAF'}; + this._adExtraDataKeys = {'adPosition':'_SAP', 'breakSize':'_SBS', 'breakType':'_SBT'}; + this._eventDataKeys = {'listID':'_SL'}; + this._reservedDataKeys = {'autoPlay':true}; + + //public methods + this.setVideoObject = function(video) { + this.videoObject = video; + } + + this.newProgram = function(programID, programData) { + this._init(); + this.programs[programID] = {"state": "new", "started": false, "program_started": false, "last_action_time": null, "data": this._clone(programData), "extradata": {}}; + this._validateParams(this.programs[programID]["data"]); + this._sendHit(programID, null, "data", "streamcontent", []); + } + + this.newAd = function(adID, adData) { + this._init(); + this.ads[adID] = {"state": "new", "started": false, "last_action_time": null, "currentProgramID": null, "currentAdPosition": null, "data": this._clone(adData), "extradata": {}}; + this._validateParams(this.ads[adID]["data"]); + this._sendHit(null, adID, "data", "streamspot", []); + } + + this.programEvent = function(programID, offset, eventType, eventData) { + eventData = eventData || {}; + if (this.programs[programID]) { + this._updateCustomProgramData(programID, eventData); + this.hitsCounter = (programID==this.currentProgramID)?(this.hitsCounter+1):1; + this.currentProgramID = programID; + if (this.hitsCounter<=2000) { + if (eventType == "play") { + this._playProgram(programID, offset, eventData); + } else if (eventType == "chngQual" || eventType == "chngRes" || eventType == "chngVol") { + this._changeParam(programID, null, offset, eventType, eventData); + } else { + this._event(programID, null, offset, eventType, eventData); + } + } else { + this._stopAll(); + } + } + } + + this.adEvent = function(programID, adID, offset, eventType, eventData) { + eventData = eventData || {}; + if (this.programs[programID] && this.ads[adID]) { + this._updateCustomAdData(adID, eventData); + this.hitsCounter = (programID==this.currentProgramID)?(this.hitsCounter+1):1; + this.currentProgramID = programID; + if (this.hitsCounter<=2000) { + if (eventType == "play") { + this._playAd(programID, adID, offset, eventData); + } else if (eventType == "chngQual" || eventType == "chngRes" || eventType == "chngVol") { + this._changeParam(programID, adID, offset, eventType, eventData); + } else { + this._event(programID, adID, offset, eventType, eventData); + } + } else { + this._stopAll(); + } + } + } + + this.dispose = function() { + this._dispose(); + } + + //private methods + this._playProgram = function(programID, offset, eventData) { + this._stopAll(); + var eventCategory = (this.programs[programID]['program_started']==false)?"programstart":(this.programs[programID]["started"]?"play":"start"); + var params = ["_SCO="+offset, "_SED="+this._updateActionTime(this.programs[programID])]; + if (typeof eventData['autoPlay'] != "undefined") params = params.concat(["_ECA=" + (eventData['autoPlay']?1:0)]); + if (typeof eventData['partID'] != "undefined") this.programs[programID]["extradata"]["partID"] = eventData['partID']; + else delete this.programs[programID]["extradata"]["partID"]; + if (typeof eventData['volume'] != "undefined") params = params.concat(["_SPVN=" + eventData['volume']]); + if (typeof eventData['resolution'] != "undefined") params = params.concat(["_SPRN=" + eventData['resolution']]); + this.programs[programID]["state"] = "play"; + this.programs[programID]["started"] = true; + this.programs[programID]["program_started"] = true; + this._sendHit(programID, null, "stream", eventCategory, params); + + if (typeof eventData['volume'] != "undefined") this.playerData['volume'] = eventData['volume']; + if (typeof eventData['resolution'] != "undefined") this.playerData['resolution'] = eventData['resolution']; + + for (var adID in this.ads) { + this.ads[adID]["started"] = false; + } + + for (var pID in this.programs) { + if (pID != programID) { + this.programs[pID]["started"] = false; + this.programs[pID]["program_started"] = false; + } + } + } + + this._playAd = function(programID, adID, offset, eventData) { + this._stopAll(); + var start = (!this.ads[adID]["started"] || this.ads[adID]["currentProgramID"]!=programID || this.ads[adID]["currentAdPosition"]!=eventData['adPosition']); + var breakType = this._getBreakType(programID, offset); + var eventCategory = (start && breakType!="post" && this.programs[programID]['program_started']==false)?"programstart":(start?"start":"play"); + var params = ["_SCO="+offset,"_SED="+this._updateActionTime(this.ads[adID])]; + if (typeof eventData['autoPlay'] != "undefined") params = params.concat(["_ECA=" + (eventData['autoPlay']?1:0)]); + if (typeof eventData['adPosition'] != "undefined") this.ads[adID]["extradata"]["adPosition"] = eventData['adPosition']; + else delete this.ads[adID]["extradata"]["adPosition"]; + if (typeof eventData['breakSize'] != "undefined") this.ads[adID]["extradata"]["breakSize"] = eventData['breakSize']; + else delete this.ads[adID]["extradata"]["breakSize"]; + if (breakType) this.ads[adID]["extradata"]["breakType"] = breakType; + else delete this.ads[adID]["extradata"]["breakType"]; + if (typeof eventData['volume'] != "undefined") params = params.concat(["_SPVN=" + eventData['volume']]); + if (typeof eventData['resolution'] != "undefined") params = params.concat(["_SPRN=" + eventData['resolution']]); + this.ads[adID]["state"] = "play"; + this.ads[adID]["started"] = true; + this.ads[adID]["currentProgramID"] = programID; + this.ads[adID]["currentAdPosition"] = eventData['adPosition']; + if (breakType!="post") this.programs[programID]["program_started"] = true; + this._sendHit(programID, adID, "stream", eventCategory, params); + + if (typeof eventData['volume'] != "undefined") this.playerData['volume'] = eventData['volume']; + if (typeof eventData['resolution'] != "undefined") this.playerData['resolution'] = eventData['resolution']; + } + + this._event = function(programID, adID, offset, eventType, eventData) { + var evtypes = {"pause":"pause", "stop":"stop", "close":"close", "buffer":"buffering", "break":"break", "seek":"seek", "complete":"complete", "skip":"skip", "next":"next", "prev":"prev"}; + var data = (adID?this.ads[adID]:this.programs[programID]); + if (evtypes[eventType]) { + var params = ["_SED="+this._updateActionTime(data)].concat(this._convertEventParams(eventData)); + if (typeof offset != "undefined") params = params.concat(["_SCO="+offset]); + if (eventType == "stop" || eventType == "complete" || eventType == "close") { + data["started"] = false; + if (!adID) this.programs[programID]["program_started"] = false; + } + data["state"] = evtypes[eventType]; + this._sendHit(programID, adID, "stream", evtypes[eventType], params); + } + } + + this._changeParam = function(programID, adID, offset, eventType, eventData) { + var data = (adID?this.ads[adID]:this.programs[programID]); + var params = ["_SED="+this._updateActionTime(data)]; + if (typeof offset != "undefined") params = params.concat(["_SCO="+offset]); + if (typeof eventData['volume'] != "undefined") params = params.concat(["_SPVN=" + eventData['volume']]); + if (typeof eventData['resolution'] != "undefined") params = params.concat(["_SPRN=" + eventData['resolution']]); + if (typeof eventData['quality'] != "undefined") params = params.concat([(adID?"_SAQN=":"_SCQN=") + eventData['quality']]); + this._sendHit(programID, adID, "stream", "continue", params); + + if (eventData['quality']) data['data']['quality'] = eventData['quality']; + if (eventData['resolution']) this.playerData['resolution'] = eventData['resolution']; + if (eventData['volume']) this.playerData['volume'] = eventData['volume']; + } + + this._getBreakType = function(programID, offset) { + try { + var duration = (this.programs[programID]['data']['programDuration'] || 0); + var transmissionType = (this.programs[programID]['data']['transmissionType'] || 0); + if (typeof duration != "number") duration = parseInt(duration,10); + if (typeof transmissionType != "number") transmissionType = parseInt(transmissionType,10); + if (typeof offset != "number") offset = parseInt(offset,10); + if (transmissionType==2) return "live"; + else if (duration<0) return "unknown"; + else if ((duration<=100 && offset<=0) || (duration>100 && offset<5)) return "pre"; + else if (duration>0 && ((duration<=100 && offset>=duration) || (duration>100 && offset>duration-5))) return "post"; + else return "mid"; + } catch (e) { + return ""; + } + } + + this._stopAll = function() { + for (var programID in this.programs) { + if (this.programs[programID]["state"] == "play") { + this._event(programID, null, undefined, "pause", {}); + } + } + + for (var adID in this.ads) { + if (this.ads[adID]["state"] == "play" && this.programs[this.ads[adID]["currentProgramID"]]) { + this._event(this.ads[adID]["currentProgramID"], adID, undefined, "pause", {}); + } + } + } + + this._update = function() { + var vis = GemiusPlayerVisibility.check(this.videoObject); + var res = this._getPlayerSize(); + if (vis !== this.visible || res !== this.resolution) { + this._continue(); + this.visible = vis; + this.resolution = res; + } + } + + this._getPlayerSize = function() { + if (!this.videoObject) { + return null; + } else { + try { + var rect = this.videoObject.getBoundingClientRect(); + return parseInt(rect.width,10) + "x" + parseInt(rect.height,10); + } catch (e) { + return null; + } + } + } + + this._continue = function() { + for (var programID in this.programs) { + if (this.programs[programID]["state"] == "play") { + var params = ["_SED="+this._updateActionTime(this.programs[programID])]; + this._sendHit(programID, null, "stream", "continue", params); + } + } + for (var adID in this.ads) { + if (this.ads[adID]["state"] == "play") { + var params = ["_SED="+this._updateActionTime(this.ads[adID])]; + this._sendHit(this.ads[adID]["currentProgramID"], adID, "stream", "continue", params); + } + } + } + + this._sendClosingHits = function(eventCategory) { + try { + if (typeof gemius_close == 'function') { + gemius_close(); + } + var delay = false; + for (var programID in this.programs) { + if (this.programs[programID]["state"] == "play") { + var params = ["_SED="+this._updateActionTime(this.programs[programID])]; + this._sendHit(programID, null, "stream", eventCategory, params); + delay = true; + } + } + for (var adID in this.ads) { + if (this.ads[adID]["state"] == "play") { + var params = ["_SED="+this._updateActionTime(this.ads[adID])]; + this._sendHit(this.ads[adID]["currentProgramID"], adID, "stream", eventCategory, params); + delay = true; + } + } + if (delay && typeof navigator.sendBeacon != "function") { + var start = (new Date()).getTime(); + while (start+250>(new Date()).getTime()); + } + } catch(e) {} + } + + this._unload = function() { + this._sendClosingHits("unload"); + } + + this._pagehide = function() { + this._unload(); + if (this.hidetime == null) { + this.hidetime = (new Date()).getTime(); + } + } + + this._pageshow = function() { + if (this.hidetime == null) { + return; + } + var showtime = ((new Date()).getTime()); + var leap = (showtime > this.hidetime) ? showtime - this.hidetime : 0; + try { + for (var programID in this.programs) { + this._updateHideTime(this.programs[programID], leap); + } + for (var adID in this.ads) { + this._updateHideTime(this.ads[adID], leap); + } + } catch(e) {} + this.hidetime = null; + } + + this._updateHideTime = function(streamData, leap) { + try { + if (streamData['state'] == 'play' && streamData['last_action_time']) { + streamData['last_action_time'] += leap; + } + } catch(e) {} + } + + this._updateActionTime = function(streamData) { + var duration = 0; + try { + if (streamData['state'] == 'play' && streamData['last_action_time']) { + duration = Math.round(((new Date()).getTime() - streamData['last_action_time']) / 1000); + if (duration < 0 || duration > 2*this.interval) { + duration = 0; + } + } + streamData['last_action_time'] = (new Date()).getTime(); + } catch (e) {} + return duration; + } + + this._sendHit = function(programID, adID, eventType, eventCategory, params) { + if (this.disposed) { + return; + } + var extra = ["_EC="+eventCategory].concat(this._getPlayerParams()).concat(this._getProgramParams(programID)).concat(this._getAdParams(adID)).concat(params); + gemius_event.apply(window, ['_' + eventType + '_', this.gemiusID].concat(extra)); + } + + this._getProgramParams = function(programID) { + if (!this.programs[programID]) return []; + var params = ["_SC="+programID]; + params = params.concat(this._convertParams(this.programs[programID]["data"], this._programDataKeys, true)); + params = params.concat(this._convertParams(this.programs[programID]["extradata"], this._programExtraDataKeys)); + return params; + } + + this._getAdParams = function(adID) { + if (!this.ads[adID]) return []; + var params = ["_SA="+adID]; + params = params.concat(this._convertParams(this.ads[adID]["data"], this._adDataKeys, true)); + params = params.concat(this._convertParams(this.ads[adID]["extradata"], this._adExtraDataKeys)); + return params; + } + + this._getPlayerParams = function() { + var params = ["_SPI="+this.instanceID,"_SP="+this.playerID]; + if (this.resolution !== null) params = params.concat(["_SPS="+this.resolution]); + if (this.visible !== null) params = params.concat(["_SPIS="+(this.visible?"1":"0")]); + return params.concat(this._convertParams(this.playerData,this._playerDataKeys)); + } + + this._validateParams = function(params) { + var intTypes = {'programDuration':1, 'adDuration':1}; + var maxLengths = {'programTransmission':20,'adTransmission':20,'programPartialName':64,'programProducer':64, + 'programSeason':64,'transmissionChannel':64,'transmissionStartTime':10}; + if (typeof params != 'undefined') { + for (var key in params) { + if (maxLengths[key]) { + if (typeof params[key] == 'string') { + params[key] = params[key].substr(0, maxLengths[key]); + } else { + delete params[key]; + } + } + if (intTypes[key]) { + params[key] = parseInt(params[key]); + } + } + } + } + + this._convertEventParams = function(eventData) { + return this._convertParams(eventData, this._eventDataKeys); + } + + this._convertParams = function(params, keyMap, allowCustomParams) { + var res = []; + if (typeof params != 'undefined') { + for (var key in params) { + if (keyMap[key] || allowCustomParams) { + res[res.length] = (keyMap[key] || key) + "=" + params[key]; + } + } + } + return res; + } + + this._updateCustomProgramData = function(programID, eventData) { + for (var key in eventData) { + if (!(key in this._reservedDataKeys)) { + this.programs[programID]['data'][key] = eventData[key]; + } + } + this._validateParams(this.programs[programID]['data']); + } + + this._updateCustomAdData = function(adID, eventData) { + for (var key in eventData) { + if (!(key in this._reservedDataKeys)) { + this.ads[adID]['data'][key] = eventData[key]; + } + } + this._validateParams(this.ads[adID]['data']); + } + + this._assignDataKeys = function(target, source) { + for (var key in source) { + target[key] = true; + } + } + + this._initReservedKeys = function() { + this._assignDataKeys(this._reservedDataKeys, this._playerDataKeys); + this._assignDataKeys(this._reservedDataKeys, this._programDataKeys); + this._assignDataKeys(this._reservedDataKeys, this._programExtraDataKeys); + this._assignDataKeys(this._reservedDataKeys, this._adDataKeys); + this._assignDataKeys(this._reservedDataKeys, this._adExtraDataKeys); + this._assignDataKeys(this._reservedDataKeys, this._eventDataKeys); + delete this._reservedDataKeys['programDuration']; + delete this._reservedDataKeys['adDuration']; + } + + this._addEvent = function(obj,type,fn) { + if (obj.addEventListener) { + obj.addEventListener(type, fn, false); + } else if (obj.attachEvent) { + obj.attachEvent('on'+type, fn); + } + } + + this._removeEvent = function(obj,type,fn) { + if (obj.removeEventListener) { + obj.removeEventListener(type, fn, false); + } else if (obj.detachEvent) { + obj.detachEvent('on'+type, fn); + } + } + + this._init = function() { + if (!this.initialized && !this.disposed) { + this.initialized = true; + this._initReservedKeys(); + this._update(); + this.continueIntervalID = setInterval(this._wrapFun(this,"_continue"), this.interval * 1000); + this.updateIntervalID = setInterval(this._wrapFun(this,"_update"), this.updateInterval * 1000); + this.unloadFun = this._wrapFun(this,"_unload"); + this.pagehideFun = this._wrapFun(this,"_pagehide"); + this.pageshowFun = this._wrapFun(this,"_pageshow"); + try { + if ('onpagehide' in window) { + this._addEvent(window.top, 'pagehide', this.pagehideFun); + this._addEvent(window.top, 'pageshow', this.pageshowFun); + } else if (typeof navigator.sendBeacon == "function") { + this._addEvent(window.top, 'unload', this.unloadFun); + } else { + this._addEvent(window.top, 'beforeunload', this.unloadFun); + } + } catch (e) { + if ('onpagehide' in window) { + this._addEvent(window, 'pagehide', this.pagehideFun); + this._addEvent(window, 'pageshow', this.pageshowFun); + } else if (typeof navigator.sendBeacon == "function") { + this._addEvent(window, 'unload', this.unloadFun); + } else { + this._addEvent(window, 'beforeunload', this.unloadFun); + } + } + } + } + + this._dispose = function() { + if (this.initialized && !this.disposed) { + this._sendClosingHits("dispose"); + clearInterval(this.continueIntervalID); + clearInterval(this.updateIntervalID); + try { + if ('onpagehide' in window) { + this._removeEvent(window.top, 'pagehide', this.pagehideFun); + this._removeEvent(window.top, 'pageshow', this.pageshowFun); + } else if (typeof navigator.sendBeacon == "function") { + this._removeEvent(window.top, 'unload', this.unloadFun); + } else { + this._removeEvent(window.top, 'beforeunload', this.unloadFun); + } + } catch (e) { + if ('onpagehide' in window) { + this._removeEvent(window, 'pagehide', this.pagehideFun); + this._removeEvent(window, 'pageshow', this.pageshowFun); + } else if (typeof navigator.sendBeacon == "function") { + this._removeEvent(window, 'unload', this.unloadFun); + } else { + this._removeEvent(window, 'beforeunload', this.unloadFun); + } + } + this.disposed = true; + } + } + + this._wrapFun = function(self, method) { + return function() { + self[method](); + } + } + + this._clone = function(obj) { + var res = {}; + if (!obj) return res; + for (var key in obj) { + if (obj.hasOwnProperty(key)) res[key] = obj[key]; + } + return res; + } +} + +if (typeof window['gemius_player_data'] != 'undefined') { + for (var i=0; i { player.source = testAsset.source - // gemiusConnector.update(testAsset.metadata) + const newMetadata = testAsset.metadata + if (newMetadata.transmissionType === 2) newMetadata.transmissionStartTime = Date.now().toString() + console.log({newMetadata}) + gemiusConnector.update(newMetadata) } const populateSourceSelector = (testAssets) => { @@ -89,12 +92,13 @@ .then(jsonResponse => { testAssets = jsonResponse player.source = jsonResponse[0].source - // const gemiusMetadata = jsonResponse[0].metadata - // gemiusConnector = new GemiusConnector( - // player, - // gemiusConfig, - // gemiusMetadata, - // ) + const gemiusProgramMetadata = jsonResponse[0].metadata + if (gemiusProgramMetadata.transmissionType === 2) gemiusProgramMetadata.transmissionStartTime = new Date.now() + gemiusConnector = new GemiusConnector( + player, + gemiusConfig, + gemiusProgramMetadata, + ) populateSourceSelector(jsonResponse) selector.value = 0 }) diff --git a/gemius/test/pages/main_umd.html b/gemius/test/pages/main_umd.html index 4aaae407..fc905486 100644 --- a/gemius/test/pages/main_umd.html +++ b/gemius/test/pages/main_umd.html @@ -65,7 +65,9 @@ const setSourceWithGemiusMetadata = (testAsset) => { player.source = testAsset.source - // gemiusConnector.update(testAsset.metadata) + const newMetadata = testAsset.metadata + if (newMetadata.transmissionType === 2) newMetadata.transmissionStartTime = Date.now().toString() + gemiusConnector.update(newMetadata) } const populateSourceSelector = (testAssets) => { @@ -82,12 +84,13 @@ .then(jsonResponse => { testAssets = jsonResponse player.source = jsonResponse[0].source - // const gemiusMetadata = jsonResponse[0].metadata - // gemiusConnector = new THEOplayerGemiusConnector.GemiusConnector( - // player, - // gemiusConfig, - // gemiusMetadata, - // ) + const gemiusMetadata = jsonResponse[0].metadata + if (gemiusMetadata.transmissionType === 2) gemiusMetadata.transmissionStartTime = Date.now().toString() + gemiusConnector = new THEOplayerGemiusConnector.GemiusConnector( + player, + gemiusConfig, + gemiusMetadata, + ) populateSourceSelector(jsonResponse) selector.value = 0 }) diff --git a/gemius/test/pages/preroll-empty.xml b/gemius/test/pages/preroll-empty.xml new file mode 100644 index 00000000..6850c951 --- /dev/null +++ b/gemius/test/pages/preroll-empty.xml @@ -0,0 +1 @@ + \ No newline at end of file From 398f4e2e8faf5ac522c66625e6ac7f6ab62d5b8f Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 16 Jul 2024 23:19:11 +0200 Subject: [PATCH 24/52] use duration from passed program parameters --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index e83e439d..cc41aa27 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -135,7 +135,7 @@ export class GemiusTHEOIntegration { partID: this.partCount, // resolution: `AxB`; TODO volume: computedVolume, - programDuration: this.player.duration + programDuration: this.programParameters.programDuration }) } } From c28e212d274c68bf6424e362f7a7b43699eed920 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 16 Jul 2024 23:20:04 +0200 Subject: [PATCH 25/52] update test asset metadata --- gemius/test/pages/test-assets.json | 180 +++++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 7 deletions(-) diff --git a/gemius/test/pages/test-assets.json b/gemius/test/pages/test-assets.json index 72010fd2..55772faf 100644 --- a/gemius/test/pages/test-assets.json +++ b/gemius/test/pages/test-assets.json @@ -1,4 +1,38 @@ [ + { + "label": "VOD (DASH) + VAST (IMA)", + "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": { + "programID": "000001", + "programName": "Big Buck Bunny (DASH)", + "programDuration": 635, + "programType": "video", + "transmissionType": 1, + "programGenre": 4, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "Blender", + "customAttributes": { + "intCategory": "Comedy", + "intType": "vod", + "intStatus": "public" + } + } + }, { "label": "VOD (HLS)", "source": { @@ -9,7 +43,23 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000002", + "programName": "Big Buck Bunny (HLS)", + "programDuration": 596, + "programType": "video", + "transmissionType": 1, + "programGenre": 4, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "Blender", + "customAttributes": { + "intName": "BBB", + "intCategory": "Comedy", + "intType": "vod", + "intStatus": "public" + } + } }, { "label": "VOD (HLS) - VMAP (IMA)", @@ -27,7 +77,23 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000002", + "programName": "Big Buck Bunny (HLS)", + "programDuration": 596, + "programType": "video", + "transmissionType": 1, + "programGenre": 4, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "Blender", + "customAttributes": { + "intName": "BBB", + "intCategory": "Comedy", + "intType": "vod", + "intStatus": "public" + } + } }, { "label": "VOD (HLS) - VMAP (THEOAds)", @@ -45,7 +111,23 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000002", + "programName": "Big Buck Bunny (HLS)", + "programDuration": 596, + "programType": "video", + "transmissionType": 1, + "programGenre": 4, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "Blender", + "customAttributes": { + "intName": "BBB", + "intCategory": "Comedy", + "intType": "vod", + "intStatus": "public" + } + } }, { "label": "LIVE (DASH) - VAST pre-roll (IMA)", @@ -64,7 +146,59 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000003", + "programName": "Livesim", + "programDuration": -1, + "programType": "video", + "transmissionType": 2, + "transmissionChannel": "DASHIF1", + "programGenre": 1, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "DASHIF", + "customAttributes": { + "intName": "LIVESIM", + "intCategory": "Generic", + "intType": "vod", + "intStatus": "public" + } + } + }, + { + "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/gemius/test/pages/preroll-empty.xml" + } + ] + }, + "metadata": { + "programID": "000003", + "programName": "Livesim", + "programDuration": -1, + "programType": "video", + "transmissionType": 2, + "programGenre": 1, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "DASHIF", + "customAttributes": { + "intName": "LIVESIM", + "intCategory": "Generic", + "intType": "vod", + "intStatus": "public" + } + } }, { "label": "LIVE (DASH) - VAST pre-roll (THEOAds)", @@ -83,7 +217,23 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000003", + "programName": "Livesim", + "programDuration": -1, + "programType": "video", + "transmissionType": 2, + "programGenre": 1, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "DASHIF", + "customAttributes": { + "intName": "LIVESIM", + "intCategory": "Generic", + "intType": "vod", + "intStatus": "public" + } + } }, { "label": "VOD - Google DAI", @@ -94,7 +244,7 @@ "ssai": { "integration": "google-dai", "availabilityType": "vod", - "contentSourceID": "2528370", + "contentSourceID": "2548831", "videoID": "tears-of-steel", "assetKey": "", "apiKey": "" @@ -102,6 +252,22 @@ } ] }, - "metadata": {} + "metadata": { + "programID": "000003", + "programName": "Livesim", + "programDuration": 794, + "programType": "video", + "transmissionType": 1, + "programGenre": 4, + "series": "Test Content", + "programSeason": "season 1", + "programProducer": "Blender Foundation", + "customAttributes": { + "intName": "TOS", + "intCategory": "Generic", + "intType": "vod", + "intStatus": "public" + } + } } ] \ No newline at end of file From ccc0d8544ddd3e162b0ce34a76f92d27939572c6 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 16 Jul 2024 23:20:39 +0200 Subject: [PATCH 26/52] reference for player instance --- gemius/test/pages/main_esm.html | 1 + 1 file changed, 1 insertion(+) diff --git a/gemius/test/pages/main_esm.html b/gemius/test/pages/main_esm.html index da70403a..b2a63d90 100644 --- a/gemius/test/pages/main_esm.html +++ b/gemius/test/pages/main_esm.html @@ -69,6 +69,7 @@ libraryLocation: "/node_modules/theoplayer/", license: "" }); + window.player = player const setSourceWithGemiusMetadata = (testAsset) => { player.source = testAsset.source From c2b62a8c3a36c7b553eab76745fc46c5ce9162d9 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Tue, 16 Jul 2024 23:44:18 +0200 Subject: [PATCH 27/52] report newAd --- .../src/integration/GemiusTHEOIntegration.ts | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index cc41aa27..7ec57f44 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -5,7 +5,9 @@ import { AdSkipEvent, AddTrackEvent, ChromelessPlayer, + DurationChangeEvent, EndedEvent, + GoogleImaAd, MediaTrack, PauseEvent, PlayEvent, @@ -24,7 +26,6 @@ import { Logger } from '../utils/Logger'; import { BasicEvent } from './GemiusEvents'; const THEOPLAYER_ID = "THEOplayer" - const DEFAULT_AD_ID = "PLACEHOLDER ID" export class GemiusTHEOIntegration { @@ -38,6 +39,8 @@ export class GemiusTHEOIntegration { private adCount: number = 1; private currentAd: Ad | undefined; + private mainContentDuration: number | undefined; + constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { this.player = player; this.debug = configuration.debug ?? false; @@ -57,6 +60,7 @@ export class GemiusTHEOIntegration { private addListeners(): void { this.player.addEventListener('sourcechange', this.onSourceChange); + this.player.addEventListener('durationchange', this.onDurationChange); this.player.addEventListener('play', this.onPlay); this.player.addEventListener('pause', this.onPause); this.player.addEventListener('waiting', this.onWaiting); @@ -76,6 +80,7 @@ export class GemiusTHEOIntegration { private removeListeners(): void { this.player.removeEventListener('sourcechange', this.onSourceChange); + this.player.addEventListener('durationchange', this.onDurationChange); this.player.removeEventListener('play', this.onPlay); this.player.removeEventListener('pause', this.onPause); this.player.removeEventListener('waiting', this.onWaiting); @@ -106,6 +111,7 @@ export class GemiusTHEOIntegration { this.reportBasicEvent(BasicEvent.CLOSE) return; } + this.mainContentDuration = undefined; this.reportBasicEvent(BasicEvent.CLOSE) this.partCount = 1; this.currentAd = undefined; @@ -114,6 +120,13 @@ export class GemiusTHEOIntegration { this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) }; + private onDurationChange = (event: DurationChangeEvent) => { + Logger.log(event); + if (this.player.ads?.playing) return; + const { duration } = event + this.mainContentDuration = duration; + } + private onPlay = (event: PlayEvent) => { Logger.log(event); const { programID } = this.programParameters; @@ -212,7 +225,20 @@ export class GemiusTHEOIntegration { private onAdBegin = (event: AdEvent<'adbegin'>) => { Logger.log(event); const { ad } = event; + const { adBreak } = ad; this.currentAd = ad + const { id, duration, width, height } = ad + const { clientWidth, clientHeight } = this.player.element; + this.gemiusPlayer.newAd(id ?? DEFAULT_AD_ID, { + adName: ad.integration?.includes("google") ? (ad as GoogleImaAd).title ?? "" : "", + adDuration: duration, + adType: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), + // TODO campaignClassification + adFormat: 1, + quality: `${width}x${height}`, + resolution: `${clientWidth}x${clientHeight}`, + volume: this.player.muted ? -1 : (this.player.volume * 100) + }) } @@ -244,4 +270,12 @@ export class GemiusTHEOIntegration { this.gemiusPlayer.programEvent(programID,currentTime, event) } } + + 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" + } } From 32d66d5950880150452e06eff4c0de8eaf98344b Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Wed, 17 Jul 2024 00:06:24 +0200 Subject: [PATCH 28/52] correct adtype mistake --- .../src/integration/GemiusTHEOIntegration.ts | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 7ec57f44..bc9465f8 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -5,7 +5,6 @@ import { AdSkipEvent, AddTrackEvent, ChromelessPlayer, - DurationChangeEvent, EndedEvent, GoogleImaAd, MediaTrack, @@ -21,7 +20,7 @@ import { } from 'theoplayer'; import type { GemiusPlayer } from '../gemius/Gemius'; import { GemiusConfiguration } from './GemiusConfiguration'; -import { GemiusProgramParameters } from './GemiusParameters'; +import { AdType, GemiusProgramParameters } from './GemiusParameters'; import { Logger } from '../utils/Logger'; import { BasicEvent } from './GemiusEvents'; @@ -39,8 +38,6 @@ export class GemiusTHEOIntegration { private adCount: number = 1; private currentAd: Ad | undefined; - private mainContentDuration: number | undefined; - constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { this.player = player; this.debug = configuration.debug ?? false; @@ -60,7 +57,6 @@ export class GemiusTHEOIntegration { private addListeners(): void { this.player.addEventListener('sourcechange', this.onSourceChange); - this.player.addEventListener('durationchange', this.onDurationChange); this.player.addEventListener('play', this.onPlay); this.player.addEventListener('pause', this.onPause); this.player.addEventListener('waiting', this.onWaiting); @@ -80,7 +76,6 @@ export class GemiusTHEOIntegration { private removeListeners(): void { this.player.removeEventListener('sourcechange', this.onSourceChange); - this.player.addEventListener('durationchange', this.onDurationChange); this.player.removeEventListener('play', this.onPlay); this.player.removeEventListener('pause', this.onPause); this.player.removeEventListener('waiting', this.onWaiting); @@ -95,7 +90,6 @@ export class GemiusTHEOIntegration { this.player.ads.removeEventListener('adbegin', this.onAdBegin) this.player.ads.removeEventListener('adend', this.onAdEnd) this.player.ads.removeEventListener('adskip', this.onAdSkip) - } } @@ -111,7 +105,6 @@ export class GemiusTHEOIntegration { this.reportBasicEvent(BasicEvent.CLOSE) return; } - this.mainContentDuration = undefined; this.reportBasicEvent(BasicEvent.CLOSE) this.partCount = 1; this.currentAd = undefined; @@ -120,13 +113,6 @@ export class GemiusTHEOIntegration { this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) }; - private onDurationChange = (event: DurationChangeEvent) => { - Logger.log(event); - if (this.player.ads?.playing) return; - const { duration } = event - this.mainContentDuration = duration; - } - private onPlay = (event: PlayEvent) => { Logger.log(event); const { programID } = this.programParameters; @@ -225,14 +211,13 @@ export class GemiusTHEOIntegration { private onAdBegin = (event: AdEvent<'adbegin'>) => { Logger.log(event); const { ad } = event; - const { adBreak } = ad; this.currentAd = ad const { id, duration, width, height } = ad const { clientWidth, clientHeight } = this.player.element; this.gemiusPlayer.newAd(id ?? DEFAULT_AD_ID, { adName: ad.integration?.includes("google") ? (ad as GoogleImaAd).title ?? "" : "", adDuration: duration, - adType: this.getAdType(adBreak.timeOffset, this.player.duration, adBreak.integration), + adType: AdType.BREAK, // TODO campaignClassification adFormat: 1, quality: `${width}x${height}`, @@ -271,11 +256,4 @@ export class GemiusTHEOIntegration { } } - 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" - } } From 21662bae337128371a10dff40367e2d4f2508a13 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Thu, 18 Jul 2024 23:54:11 +0200 Subject: [PATCH 29/52] normalize time for DAI sources --- .../src/integration/GemiusTHEOIntegration.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index bc9465f8..1a01f3c1 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -120,7 +120,8 @@ export class GemiusTHEOIntegration { if (this.currentAd) { const { id, adBreak, duration } = this.currentAd; const { timeOffset, ads } = adBreak - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, "play", { + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "play", { autoPlay: true, adPosition: this.adCount, breakSize: ads?.length, @@ -167,7 +168,8 @@ export class GemiusTHEOIntegration { if (this.currentAd) { const { id, adBreak } = this.currentAd; const { timeOffset } = adBreak - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, "chngVol", { volume: computedVolume }); // TODO make SSAI ready + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "chngVol", { volume: computedVolume }); // TODO make SSAI ready } else { const { currentTime } = this.player this.gemiusPlayer.programEvent(programID, currentTime, "chngVol", { volume: computedVolume}) @@ -199,7 +201,11 @@ export class GemiusTHEOIntegration { Logger.log(event); const { programID } = this.programParameters const { adBreak } = event - this.gemiusPlayer.programEvent(programID, adBreak.timeOffset, "break"); + const { timeOffset } = adBreak + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, "break"); + this.player.removeEventListener('playing',this.onFirstPlaying); + this.player.addEventListener('playing',this.onFirstPlaying); } private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { @@ -231,7 +237,10 @@ export class GemiusTHEOIntegration { Logger.log(event); const { programID } = this.programParameters const { ad } = event - this.gemiusPlayer.programEvent(programID, ad.adBreak.timeOffset, BasicEvent.COMPLETE); + const { adBreak } = ad; + const { timeOffset} = adBreak + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, BasicEvent.COMPLETE); this.adCount++ this.currentAd = undefined; } @@ -240,7 +249,10 @@ export class GemiusTHEOIntegration { Logger.log(event); const { programID } = this.programParameters const { ad } = event - this.gemiusPlayer.programEvent(programID, ad.adBreak.timeOffset, BasicEvent.SKIP); + const { adBreak } = ad + const { timeOffset} = adBreak + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, BasicEvent.SKIP); } @@ -250,7 +262,8 @@ export class GemiusTHEOIntegration { if (this.currentAd) { const { id, adBreak } = this.currentAd; const { timeOffset } = adBreak - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, timeOffset, event); // TODO make SSAI ready + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, event); // TODO make SSAI ready } else { this.gemiusPlayer.programEvent(programID,currentTime, event) } From c68646344651d74d21dd8a88b6900832ddc56da7 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Thu, 18 Jul 2024 23:55:27 +0200 Subject: [PATCH 30/52] use first playing events to signal switches between ads / main content --- .../src/integration/GemiusTHEOIntegration.ts | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 1a01f3c1..5f0a9e7f 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -1,5 +1,6 @@ import { Ad, + AdBreak, AdBreakEvent, AdEvent, AdSkipEvent, @@ -10,6 +11,7 @@ import { MediaTrack, PauseEvent, PlayEvent, + PlayingEvent, QualityEvent, RemoveTrackEvent, SeekingEvent, @@ -57,7 +59,7 @@ export class GemiusTHEOIntegration { private addListeners(): void { this.player.addEventListener('sourcechange', this.onSourceChange); - this.player.addEventListener('play', this.onPlay); + this.player.addEventListener('playing', this.onFirstPlaying); this.player.addEventListener('pause', this.onPause); this.player.addEventListener('waiting', this.onWaiting); this.player.addEventListener('seeking', this.onSeeking); @@ -76,7 +78,7 @@ export class GemiusTHEOIntegration { private removeListeners(): void { this.player.removeEventListener('sourcechange', this.onSourceChange); - this.player.removeEventListener('play', this.onPlay); + this.player.removeEventListener('playing', this.onFirstPlaying); this.player.removeEventListener('pause', this.onPause); this.player.removeEventListener('waiting', this.onWaiting); this.player.removeEventListener('seeking', this.onSeeking); @@ -113,7 +115,7 @@ export class GemiusTHEOIntegration { this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) }; - private onPlay = (event: PlayEvent) => { + private onFirstPlaying = (event: PlayingEvent) => { Logger.log(event); const { programID } = this.programParameters; const computedVolume = this.player.muted ? -1 : (this.player.volume * 100) @@ -130,7 +132,10 @@ export class GemiusTHEOIntegration { adDuration: duration }) } else { - this.gemiusPlayer.programEvent(programID, this.player.currentTime, "play", { + if (this.player.ads?.scheduledAdBreaks.some(adBreak => adBreak.timeOffset === 0)) return; + const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime + console.log(`play event with partID = ${this.partCount}`) + this.gemiusPlayer.programEvent(programID, offset, "play", { autoPlay: this.player.autoplay, partID: this.partCount, // resolution: `AxB`; TODO @@ -138,6 +143,7 @@ export class GemiusTHEOIntegration { programDuration: this.programParameters.programDuration }) } + this.player.removeEventListener('playing',this.onFirstPlaying) } private onPause = (event: PauseEvent) => { @@ -210,8 +216,12 @@ export class GemiusTHEOIntegration { private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { Logger.log(event); - this.partCount++ this.adCount = 1; + const { adBreak } = event; + if (!this.isPreRoll(adBreak) )this.partCount++ + console.log(` partCount = ${this.partCount}`) + this.player.removeEventListener('playing',this.onFirstPlaying); + this.player.addEventListener('playing',this.onFirstPlaying); } private onAdBegin = (event: AdEvent<'adbegin'>) => { @@ -243,6 +253,8 @@ export class GemiusTHEOIntegration { this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, BasicEvent.COMPLETE); this.adCount++ this.currentAd = undefined; + this.player.removeEventListener('playing',this.onFirstPlaying); + this.player.addEventListener('playing',this.onFirstPlaying); } private onAdSkip = (event: AdSkipEvent) => { @@ -269,4 +281,12 @@ export class GemiusTHEOIntegration { } } + private normalizeTime = (time: number) => { + return this.player.ads?.dai?.contentTimeForStreamTime(time) ?? time; + } + + private isPreRoll = (adBreak: AdBreak) => { + return adBreak.timeOffset === 0 + } + } From 1c5a05fd321b96552c69eaa43b47489de2c99802 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:09:27 +0200 Subject: [PATCH 31/52] only report play for main content the first time --- gemius/src/integration/GemiusTHEOIntegration.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 5f0a9e7f..30d3dede 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -218,10 +218,11 @@ export class GemiusTHEOIntegration { Logger.log(event); this.adCount = 1; const { adBreak } = event; + const { timeOffset } = adBreak; if (!this.isPreRoll(adBreak) )this.partCount++ console.log(` partCount = ${this.partCount}`) this.player.removeEventListener('playing',this.onFirstPlaying); - this.player.addEventListener('playing',this.onFirstPlaying); + if (timeOffset === 0) this.player.addEventListener('playing',this.onFirstPlaying); } private onAdBegin = (event: AdEvent<'adbegin'>) => { From 2740075deb763219c54aa739633c70ccb87169e1 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:09:51 +0200 Subject: [PATCH 32/52] close both the ad and main playback session on source change --- gemius/src/integration/GemiusTHEOIntegration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 30d3dede..74fc2e81 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -277,9 +277,8 @@ export class GemiusTHEOIntegration { const { timeOffset } = adBreak const normalizedTimeOffset = this.normalizeTime(timeOffset) this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, event); // TODO make SSAI ready - } else { - this.gemiusPlayer.programEvent(programID,currentTime, event) } + this.gemiusPlayer.programEvent(programID,currentTime, event) } private normalizeTime = (time: number) => { From 4b925197a105401ac4b5dd0e1567ee6d56405003 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:10:04 +0200 Subject: [PATCH 33/52] remove unused import --- gemius/src/integration/GemiusTHEOIntegration.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 74fc2e81..ed7be4f6 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -10,7 +10,6 @@ import { GoogleImaAd, MediaTrack, PauseEvent, - PlayEvent, PlayingEvent, QualityEvent, RemoveTrackEvent, From 49da5a03c5aac559035f68e5c4e2958111157d31 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:40:22 +0200 Subject: [PATCH 34/52] report calls to play() --- .../src/integration/GemiusTHEOIntegration.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index ed7be4f6..3df74ca7 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -59,6 +59,7 @@ export class GemiusTHEOIntegration { private addListeners(): void { this.player.addEventListener('sourcechange', this.onSourceChange); this.player.addEventListener('playing', this.onFirstPlaying); + this.player.addEventListener('play', this.onPlay); this.player.addEventListener('pause', this.onPause); this.player.addEventListener('waiting', this.onWaiting); this.player.addEventListener('seeking', this.onSeeking); @@ -78,6 +79,7 @@ export class GemiusTHEOIntegration { private removeListeners(): void { this.player.removeEventListener('sourcechange', this.onSourceChange); this.player.removeEventListener('playing', this.onFirstPlaying); + this.player.removeEventListener('play', this.onPlay); this.player.removeEventListener('pause', this.onPause); this.player.removeEventListener('waiting', this.onWaiting); this.player.removeEventListener('seeking', this.onSeeking); @@ -150,6 +152,35 @@ export class GemiusTHEOIntegration { this.reportBasicEvent(BasicEvent.PAUSE) } + private onPlay = (event: PlayEvent) => { + Logger.log(event); + const { programID } = this.programParameters; + const computedVolume = this.player.muted ? -1 : (this.player.volume * 100) + if (this.currentAd) { + const { id, adBreak, duration } = this.currentAd; + const { timeOffset, ads } = adBreak + const normalizedTimeOffset = this.normalizeTime(timeOffset) + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "play", { + autoPlay: true, + adPosition: this.adCount, + breakSize: ads?.length, + // resolution: `AxB`, TODO + volume: computedVolume, + adDuration: duration + }) + } else { + if (this.player.ads?.scheduledAdBreaks.some(adBreak => adBreak.timeOffset === 0)) return; + const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime + this.gemiusPlayer.programEvent(programID, offset, "play", { + autoPlay: this.player.autoplay, + partID: this.partCount, + // resolution: `AxB`; TODO + volume: computedVolume, + programDuration: this.programParameters.programDuration + }) + } + } + private onWaiting = (event: WaitingEvent) => { Logger.log(event); this.reportBasicEvent(BasicEvent.BUFFER) From 924b8b55c78c1f896c8adfb4d4e2085ab0985854 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:41:14 +0200 Subject: [PATCH 35/52] remove logs --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 3df74ca7..e8db1326 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -135,7 +135,6 @@ export class GemiusTHEOIntegration { } else { if (this.player.ads?.scheduledAdBreaks.some(adBreak => adBreak.timeOffset === 0)) return; const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime - console.log(`play event with partID = ${this.partCount}`) this.gemiusPlayer.programEvent(programID, offset, "play", { autoPlay: this.player.autoplay, partID: this.partCount, @@ -250,7 +249,6 @@ export class GemiusTHEOIntegration { const { adBreak } = event; const { timeOffset } = adBreak; if (!this.isPreRoll(adBreak) )this.partCount++ - console.log(` partCount = ${this.partCount}`) this.player.removeEventListener('playing',this.onFirstPlaying); if (timeOffset === 0) this.player.addEventListener('playing',this.onFirstPlaying); } From bdb0791bafaf5696e6b5650e3d3d0dd12f643e76 Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:41:44 +0200 Subject: [PATCH 36/52] report complete and close on adend --- gemius/src/integration/GemiusTHEOIntegration.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index e8db1326..f3d12f41 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -279,7 +279,8 @@ export class GemiusTHEOIntegration { const { adBreak } = ad; const { timeOffset} = adBreak const normalizedTimeOffset = this.normalizeTime(timeOffset) - this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, BasicEvent.COMPLETE); + this.gemiusPlayer.adEvent(programID, ad.id ?? DEFAULT_AD_ID, normalizedTimeOffset, BasicEvent.COMPLETE); + this.gemiusPlayer.adEvent(programID, ad.id ?? DEFAULT_AD_ID, normalizedTimeOffset, BasicEvent.CLOSE); this.adCount++ this.currentAd = undefined; this.player.removeEventListener('playing',this.onFirstPlaying); From 745ec868e02b44356275c986fba8893f9df4277a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:42:15 +0200 Subject: [PATCH 37/52] set main content info again on adbreak end --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index f3d12f41..87f5afa2 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -249,6 +249,8 @@ export class GemiusTHEOIntegration { const { adBreak } = event; const { timeOffset } = adBreak; if (!this.isPreRoll(adBreak) )this.partCount++ + const { programID, customAttributes, ...additionalParameters } = this.programParameters + this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) this.player.removeEventListener('playing',this.onFirstPlaying); if (timeOffset === 0) this.player.addEventListener('playing',this.onFirstPlaying); } From 6e2673c056223297e709fbf5f19386c22a49487a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:42:29 +0200 Subject: [PATCH 38/52] prevent double reports of pause --- gemius/src/integration/GemiusTHEOIntegration.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 87f5afa2..6a1a6503 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -308,8 +308,10 @@ export class GemiusTHEOIntegration { const { timeOffset } = adBreak const normalizedTimeOffset = this.normalizeTime(timeOffset) this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, event); // TODO make SSAI ready + } + if (!this.currentAd && event !== BasicEvent.PAUSE) { + this.gemiusPlayer.programEvent(programID,currentTime, event) } - this.gemiusPlayer.programEvent(programID,currentTime, event) } private normalizeTime = (time: number) => { From 071ac306cedcee710aaa5b554716f8b011f1db9a Mon Sep 17 00:00:00 2001 From: Wonne Joosen Date: Fri, 19 Jul 2024 00:42:40 +0200 Subject: [PATCH 39/52] import PlayEvent type --- gemius/src/integration/GemiusTHEOIntegration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 6a1a6503..2034bd55 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -10,6 +10,7 @@ import { GoogleImaAd, MediaTrack, PauseEvent, + PlayEvent, PlayingEvent, QualityEvent, RemoveTrackEvent, From 9b2dcbe78079dba2031e65c6a37b39b319d633e0 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Tue, 23 Jul 2024 15:32:25 +0200 Subject: [PATCH 40/52] Add Gemius connector to workspace --- gemius/CHANGELOG.md | 7 ------- gemius/package-lock.json | 22 ---------------------- gemius/package.json | 7 +++++++ package-lock.json | 14 +++++++++++++- package.json | 3 ++- 5 files changed, 22 insertions(+), 31 deletions(-) delete mode 100644 gemius/CHANGELOG.md delete mode 100644 gemius/package-lock.json diff --git a/gemius/CHANGELOG.md b/gemius/CHANGELOG.md deleted file mode 100644 index 0410e7a4..00000000 --- a/gemius/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# @theoplayer/gemius-connector-web - -## 0.0.1 - -### ✨ Features - -- Initial release. diff --git a/gemius/package-lock.json b/gemius/package-lock.json deleted file mode 100644 index 6057de4c..00000000 --- a/gemius/package-lock.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@theoplayer/gemius-connector-web", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@theoplayer/gemius-connector-web", - "version": "0.0.1", - "license": "MIT", - "peerDependencies": { - "theoplayer": "^7.0.0" - } - }, - "node_modules/theoplayer": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-7.6.1.tgz", - "integrity": "sha512-jagM219gsaRDTGlk/uRB92y6kKqSHLkYG46d+1U69x3zBps4ATvGjbhDt4vLx+thsuu6cFNPegzvdRjaByJe8Q==", - "peer": true - } - } -} diff --git a/gemius/package.json b/gemius/package.json index 68e32a54..7f989521 100644 --- a/gemius/package.json +++ b/gemius/package.json @@ -34,6 +34,13 @@ "url": "https://github.com/THEOplayer/web-connectors/issues" }, "homepage": "https://github.com/THEOplayer/web-connectors/tree/main/gemius#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 4babe749..19b3ff52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "nielsen", "cmcd", "comscore", - "adscript" + "adscript", + "gemius" ], "devDependencies": { "@changesets/cli": "^2.27.1", @@ -85,6 +86,13 @@ } } }, + "gemius": { + "version": "0.0.1", + "license": "MIT", + "peerDependencies": { + "theoplayer": "^7.0.0" + } + }, "nielsen": { "name": "@theoplayer/nielsen-connector-web", "version": "1.1.2", @@ -2421,6 +2429,10 @@ "resolved": "conviva", "link": true }, + "node_modules/@theoplayer/gemius-connector-web": { + "resolved": "gemius", + "link": true + }, "node_modules/@theoplayer/nielsen-connector-web": { "resolved": "nielsen", "link": true diff --git a/package.json b/package.json index b56f2b8f..2676258a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "nielsen", "cmcd", "comscore", - "adscript" + "adscript", + "gemius" ], "scripts": { "changeset:version": "changeset version && node .changeset/post-process.js", From 77a2117ad70fe0c56a38ced109b786981045bd02 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Tue, 23 Jul 2024 15:32:55 +0200 Subject: [PATCH 41/52] Add changeset --- .changeset/sweet-candles-warn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-candles-warn.md diff --git a/.changeset/sweet-candles-warn.md b/.changeset/sweet-candles-warn.md new file mode 100644 index 00000000..8eda3adb --- /dev/null +++ b/.changeset/sweet-candles-warn.md @@ -0,0 +1,5 @@ +--- +"@theoplayer/gemius-connector-web": minor +--- + +Initial release. From c6e9f0dec5c2565922675274bcdbdd77ea71d25d Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:07:43 +0200 Subject: [PATCH 42/52] Run npm i --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 19b3ff52..4df815c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ }, "adscript": { "name": "@theoplayer/adscript-connector-web", - "version": "0.0.1", + "version": "0.1.0", "license": "MIT", "peerDependencies": { "theoplayer": "^7.0.0" @@ -70,7 +70,7 @@ }, "conviva": { "name": "@theoplayer/conviva-connector-web", - "version": "2.1.1", + "version": "2.1.3", "license": "MIT", "devDependencies": { "@convivainc/conviva-js-coresdk": "^4.7.4" @@ -87,6 +87,7 @@ } }, "gemius": { + "name": "@theoplayer/gemius-connector-web", "version": "0.0.1", "license": "MIT", "peerDependencies": { @@ -8762,7 +8763,7 @@ }, "yospace": { "name": "@theoplayer/yospace-connector-web", - "version": "2.2.0", + "version": "2.3.0", "license": "MIT", "peerDependencies": { "theoplayer": "^5.0.0 || ^6.0.0 || ^7.0.0" From aa10cefc0e293b543a5264a06c3217b02d85ab3c Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:08:03 +0200 Subject: [PATCH 43/52] Run prettier & lint --- gemius/src/gemius/Gemius.d.ts | 94 +++++-- gemius/src/index.ts | 2 +- gemius/src/integration/GemiusConfiguration.ts | 2 +- gemius/src/integration/GemiusConnector.ts | 20 +- gemius/src/integration/GemiusEvents.ts | 32 +-- gemius/src/integration/GemiusParameters.ts | 32 +-- .../src/integration/GemiusTHEOIntegration.ts | 234 +++++++++--------- gemius/src/utils/Logger.ts | 9 +- 8 files changed, 237 insertions(+), 188 deletions(-) diff --git a/gemius/src/gemius/Gemius.d.ts b/gemius/src/gemius/Gemius.d.ts index eba8115e..e07a457b 100644 --- a/gemius/src/gemius/Gemius.d.ts +++ b/gemius/src/gemius/Gemius.d.ts @@ -1,4 +1,4 @@ -import { +import { NewAdAdditionalParameters, NewProgramAdditionalParameters, PlayAdEventAdditionalParameters, @@ -7,56 +7,102 @@ import { ListEventAdditionalParameters, ChangeResolutionEventAddtionalParameters, ChangeVolumeEventAddtionalParameters, - ChangeQualityEventAddtionalParameters -} from "../integration/GemiusParameters"; -import { + ChangeQualityEventAddtionalParameters +} from '../integration/GemiusParameters'; +import { PlayEvent, ListEvent, ChangeResolutionEvent, ChangeVolumeEvent, ChangeQualityEvent, BreakEvent, - BasicEvent -} from '../integration/GemiusEvents' + BasicEvent +} from '../integration/GemiusEvents'; declare global { interface Window { - GemiusPlayer: typeof GemiusPlayer; + GemiusPlayer: typeof GemiusPlayer; } - } - - +} export class GemiusPlayer { constructor(playerID: string, gemiusID: string, additionalParameters?: PlayerAdditionalParameters); newProgram(programID: string, additionalParameters: NewProgramAdditionalParameters); - newAd(adId: string, additionalParameters?: NewAdAdditionalParameters) + newAd(adId: string, additionalParameters?: NewAdAdditionalParameters); // List event - programEvent(programID: string, offset: number, event: ListEvent, additionalParameters?: ListEventAdditionalParameters) + programEvent( + programID: string, + offset: number, + event: ListEvent, + additionalParameters?: ListEventAdditionalParameters + ); // Change resolution events - programEvent(programID: string, offset: number, event: ChangeResolutionEvent, additionalParameters?: ChangeResolutionEventAddtionalParameters) - adEvent(programID: string, offset: number, event: ChangeResolutionEvent, additionalParameters?: ChangeResolutionEventAddtionalParameters) + programEvent( + programID: string, + offset: number, + event: ChangeResolutionEvent, + additionalParameters?: ChangeResolutionEventAddtionalParameters + ); + adEvent( + programID: string, + offset: number, + event: ChangeResolutionEvent, + additionalParameters?: ChangeResolutionEventAddtionalParameters + ); // Change volume events - programEvent(programID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) - adEvent(programID: string, adID: string, offset: number, event: ChangeVolumeEvent, additionalParameters?: ChangeVolumeEventAddtionalParameters) + programEvent( + programID: string, + offset: number, + event: ChangeVolumeEvent, + additionalParameters?: ChangeVolumeEventAddtionalParameters + ); + adEvent( + programID: string, + adID: string, + offset: number, + event: ChangeVolumeEvent, + additionalParameters?: ChangeVolumeEventAddtionalParameters + ); // Change quality events - programEvent(programID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) - adEvent(programID: string, adID: string, offset: number, event: ChangeQualityEvent, additionalParameters?: ChangeQualityEventAddtionalParameters) + programEvent( + programID: string, + offset: number, + event: ChangeQualityEvent, + additionalParameters?: ChangeQualityEventAddtionalParameters + ); + adEvent( + programID: string, + adID: string, + offset: number, + event: ChangeQualityEvent, + additionalParameters?: ChangeQualityEventAddtionalParameters + ); // Play event - adEvent(programID: string, adID: string, offset: number, event: PlayEvent, additionalParameters: PlayAdEventAdditionalParameters) - programEvent(programID: string, offset: number, event: PlayEvent, additionalParameters: PlayProgramEventAdditionalParameters) + adEvent( + programID: string, + adID: string, + offset: number, + event: PlayEvent, + additionalParameters: PlayAdEventAdditionalParameters + ); + programEvent( + programID: string, + offset: number, + event: PlayEvent, + additionalParameters: PlayProgramEventAdditionalParameters + ); // Break event (program only) - programEvent(programID: string, offset: number, event: BreakEvent) + programEvent(programID: string, offset: number, event: BreakEvent); // Basic events for both program and ads that don't require additional parameters - adEvent(programID: string, adID: string, offset: number, event: BasicEvent) - programEvent(programID: string, offset: number, event: BasicEvent) + adEvent(programID: string, adID: string, offset: number, event: BasicEvent); + programEvent(programID: string, offset: number, event: BasicEvent); dispose(); -} \ No newline at end of file +} diff --git a/gemius/src/index.ts b/gemius/src/index.ts index e54b95bf..3a86c818 100644 --- a/gemius/src/index.ts +++ b/gemius/src/index.ts @@ -1,3 +1,3 @@ export { GemiusConnector } from './integration/GemiusConnector'; -export * from './integration/GemiusConfiguration' +export * from './integration/GemiusConfiguration'; // export * from './api/path/to/typing/helpers/etc'; diff --git a/gemius/src/integration/GemiusConfiguration.ts b/gemius/src/integration/GemiusConfiguration.ts index 61bd8263..677a3e07 100644 --- a/gemius/src/integration/GemiusConfiguration.ts +++ b/gemius/src/integration/GemiusConfiguration.ts @@ -1,4 +1,4 @@ export interface GemiusConfiguration { gemiusID: string; debug?: boolean; -} \ No newline at end of file +} diff --git a/gemius/src/integration/GemiusConnector.ts b/gemius/src/integration/GemiusConnector.ts index 57512172..b0ec4cb6 100644 --- a/gemius/src/integration/GemiusConnector.ts +++ b/gemius/src/integration/GemiusConnector.ts @@ -4,7 +4,6 @@ import { GemiusConfiguration } from './GemiusConfiguration'; import { GemiusProgramParameters } from './GemiusParameters'; export class GemiusConnector { - private gemiusIntegration: GemiusTHEOIntegration; /** @@ -12,21 +11,24 @@ export class GemiusConnector { * @param player a THEOplayer instance reference * @param configuration a configuration object for the Gemius connector * @param programParameters the parameters associated with the first source that will be set to the player - * @returns + * @returns */ - constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { - this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration, programParameters) + constructor( + player: ChromelessPlayer, + configuration: GemiusConfiguration, + programParameters: GemiusProgramParameters + ) { + this.gemiusIntegration = new GemiusTHEOIntegration(player, configuration, programParameters); } update(programParameters: GemiusProgramParameters) { - this.gemiusIntegration.update(programParameters) + this.gemiusIntegration.update(programParameters); } - /** - * Destroy + * Destroy */ destroy(): void { - this.gemiusIntegration.destroy() + this.gemiusIntegration.destroy(); } -} \ No newline at end of file +} diff --git a/gemius/src/integration/GemiusEvents.ts b/gemius/src/integration/GemiusEvents.ts index a392cf41..dba482c4 100644 --- a/gemius/src/integration/GemiusEvents.ts +++ b/gemius/src/integration/GemiusEvents.ts @@ -1,21 +1,21 @@ -export type PlayEvent = "play" -export type BreakEvent = "break" -export type ChangeResolutionEvent = "chngRes" -export type ChangeVolumeEvent = "chngVol" -export type ChangeQualityEvent = "chngQual" +export type PlayEvent = 'play'; +export type BreakEvent = 'break'; +export type ChangeResolutionEvent = 'chngRes'; +export type ChangeVolumeEvent = 'chngVol'; +export type ChangeQualityEvent = 'chngQual'; export enum ListEvent { - NEXT = "next", - PREVIOUS = "prev" + NEXT = 'next', + PREVIOUS = 'prev' } export enum BasicEvent { - STOP = "stop", - PAUSE = "pause", - BUFFER = "buffer", - SEEK = "seek", - COMPLETE = "complete", - CLOSE = "close", - SKIP = "skip", - NEXT = "next" -} \ No newline at end of file + STOP = 'stop', + PAUSE = 'pause', + BUFFER = 'buffer', + SEEK = 'seek', + COMPLETE = 'complete', + CLOSE = 'close', + SKIP = 'skip', + NEXT = 'next' +} diff --git a/gemius/src/integration/GemiusParameters.ts b/gemius/src/integration/GemiusParameters.ts index 4289a0e5..ad51cdeb 100644 --- a/gemius/src/integration/GemiusParameters.ts +++ b/gemius/src/integration/GemiusParameters.ts @@ -1,11 +1,11 @@ export enum ProgramType { - AUDIO = "audio", - VIDEO = "video" + AUDIO = 'audio', + VIDEO = 'video' } export enum TransmissionType { ON_DEMAND = 1, - BROADCAST_LIVE_TIMESHIFT = 2 + BROADCAST_LIVE_TIMESHIFT = 2 } export enum ProgramGenre { @@ -18,10 +18,10 @@ export enum ProgramGenre { } export enum AdType { - BREAK = "break", - PROMO = "promo", - SPOT = "spot", - SPONSOR = "sponsor" + BREAK = 'break', + PROMO = 'promo', + SPOT = 'spot', + SPONSOR = 'sponsor' } export enum AdFormat { @@ -49,10 +49,10 @@ export interface NewProgramAdditionalParameters { programPartialName?: string; programProducer?: string; typology?: string; - premiereDate?: string; + premiereDate?: string; externalPremiereDate?: string; - quality?: string - resolution?: string + quality?: string; + resolution?: string; volume?: number; customAttributes?: { [key: string]: string; @@ -62,7 +62,7 @@ export interface NewProgramAdditionalParameters { export interface NewAdAdditionalParameters { adName?: string; adDuration?: number; - adType?: AdType + adType?: AdType; campaignClassification?: string; adFormat?: AdFormat; quality?: string; @@ -70,7 +70,7 @@ export interface NewAdAdditionalParameters { volume?: number; customAttributes?: { [key: string]: string; - } + }; } export interface PlayAdEventAdditionalParameters { @@ -82,7 +82,7 @@ export interface PlayAdEventAdditionalParameters { adDuration?: number; customAttributes?: { [key: string]: string; - } + }; } export interface PlayProgramEventAdditionalParameters { @@ -93,11 +93,11 @@ export interface PlayProgramEventAdditionalParameters { programDuration?: number; customAttributes?: { [key: string]: string; - } + }; } export interface ListEventAdditionalParameters { - listID?: number + listID?: number; } export interface ChangeResolutionEventAddtionalParameters { @@ -114,4 +114,4 @@ export interface ChangeQualityEventAddtionalParameters { export interface GemiusProgramParameters extends NewProgramAdditionalParameters { programID: string; -} \ No newline at end of file +} diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 2034bd55..2e4f872f 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -18,7 +18,7 @@ import { SourceChangeEvent, VideoQuality, VolumeChangeEvent, - WaitingEvent, + WaitingEvent } from 'theoplayer'; import type { GemiusPlayer } from '../gemius/Gemius'; import { GemiusConfiguration } from './GemiusConfiguration'; @@ -26,8 +26,8 @@ import { AdType, GemiusProgramParameters } from './GemiusParameters'; import { Logger } from '../utils/Logger'; import { BasicEvent } from './GemiusEvents'; -const THEOPLAYER_ID = "THEOplayer" -const DEFAULT_AD_ID = "PLACEHOLDER ID" +const THEOPLAYER_ID = 'THEOplayer'; +const DEFAULT_AD_ID = 'PLACEHOLDER ID'; export class GemiusTHEOIntegration { // References for constructor arguments @@ -40,10 +40,14 @@ export class GemiusTHEOIntegration { private adCount: number = 1; private currentAd: Ad | undefined; - constructor(player: ChromelessPlayer, configuration: GemiusConfiguration, programParameters: GemiusProgramParameters) { + constructor( + player: ChromelessPlayer, + configuration: GemiusConfiguration, + programParameters: GemiusProgramParameters + ) { this.player = player; - this.debug = configuration.debug ?? false; - this.gemiusPlayer = new window.GemiusPlayer(THEOPLAYER_ID ,configuration.gemiusID, {}); + this.debug = configuration.debug ?? false; + this.gemiusPlayer = new window.GemiusPlayer(THEOPLAYER_ID, configuration.gemiusID, {}); this.programParameters = programParameters; this.addListeners(); } @@ -69,11 +73,11 @@ export class GemiusTHEOIntegration { this.player.videoTracks.addEventListener('addtrack', this.onAddTrack); this.player.videoTracks.addEventListener('removetrack', this.onRemoveTrack); if (this.player.ads) { - this.player.ads.addEventListener('adbreakbegin', this.onAdBreakBegin) - this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd) - this.player.ads.addEventListener('adbegin', this.onAdBegin) - this.player.ads.addEventListener('adend', this.onAdEnd) - this.player.ads.addEventListener('adskip', this.onAdSkip) + this.player.ads.addEventListener('adbreakbegin', this.onAdBreakBegin); + this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd); + this.player.ads.addEventListener('adbegin', this.onAdBegin); + this.player.ads.addEventListener('adend', this.onAdEnd); + this.player.ads.addEventListener('adskip', this.onAdSkip); } } @@ -89,11 +93,11 @@ export class GemiusTHEOIntegration { this.player.videoTracks.removeEventListener('addtrack', this.onAddTrack); this.player.videoTracks.removeEventListener('removetrack', this.onRemoveTrack); if (this.player.ads) { - this.player.ads.removeEventListener('adbreakbegin', this.onAdBreakBegin) - this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd) - this.player.ads.removeEventListener('adbegin', this.onAdBegin) - this.player.ads.removeEventListener('adend', this.onAdEnd) - this.player.ads.removeEventListener('adskip', this.onAdSkip) + this.player.ads.removeEventListener('adbreakbegin', this.onAdBreakBegin); + this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd); + this.player.ads.removeEventListener('adbegin', this.onAdBegin); + this.player.ads.removeEventListener('adend', this.onAdEnd); + this.player.ads.removeEventListener('adskip', this.onAdSkip); } } @@ -106,221 +110,219 @@ export class GemiusTHEOIntegration { } if (!event.source) { // TODO handle some clear source flow - this.reportBasicEvent(BasicEvent.CLOSE) + this.reportBasicEvent(BasicEvent.CLOSE); return; } - this.reportBasicEvent(BasicEvent.CLOSE) + this.reportBasicEvent(BasicEvent.CLOSE); this.partCount = 1; this.currentAd = undefined; - const { programID, customAttributes, ...additionalParameters } = this.programParameters - this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) + const { programID, customAttributes, ...additionalParameters } = this.programParameters; + this.gemiusPlayer.newProgram(programID, { ...additionalParameters, ...customAttributes }); }; private onFirstPlaying = (event: PlayingEvent) => { Logger.log(event); const { programID } = this.programParameters; - const computedVolume = this.player.muted ? -1 : (this.player.volume * 100) + const computedVolume = this.player.muted ? -1 : this.player.volume * 100; if (this.currentAd) { const { id, adBreak, duration } = this.currentAd; - const { timeOffset, ads } = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "play", { + const { timeOffset, ads } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, 'play', { autoPlay: true, adPosition: this.adCount, breakSize: ads?.length, // resolution: `AxB`, TODO volume: computedVolume, adDuration: duration - }) + }); } else { - if (this.player.ads?.scheduledAdBreaks.some(adBreak => adBreak.timeOffset === 0)) return; - const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime - this.gemiusPlayer.programEvent(programID, offset, "play", { + if (this.player.ads?.scheduledAdBreaks.some((adBreak) => adBreak.timeOffset === 0)) return; + const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime; + this.gemiusPlayer.programEvent(programID, offset, 'play', { autoPlay: this.player.autoplay, partID: this.partCount, // resolution: `AxB`; TODO volume: computedVolume, programDuration: this.programParameters.programDuration - }) + }); } - this.player.removeEventListener('playing',this.onFirstPlaying) - } + this.player.removeEventListener('playing', this.onFirstPlaying); + }; private onPause = (event: PauseEvent) => { Logger.log(event); - this.reportBasicEvent(BasicEvent.PAUSE) - } + this.reportBasicEvent(BasicEvent.PAUSE); + }; private onPlay = (event: PlayEvent) => { Logger.log(event); const { programID } = this.programParameters; - const computedVolume = this.player.muted ? -1 : (this.player.volume * 100) + const computedVolume = this.player.muted ? -1 : this.player.volume * 100; if (this.currentAd) { const { id, adBreak, duration } = this.currentAd; - const { timeOffset, ads } = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "play", { + const { timeOffset, ads } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, 'play', { autoPlay: true, adPosition: this.adCount, breakSize: ads?.length, // resolution: `AxB`, TODO volume: computedVolume, adDuration: duration - }) + }); } else { - if (this.player.ads?.scheduledAdBreaks.some(adBreak => adBreak.timeOffset === 0)) return; - const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime - this.gemiusPlayer.programEvent(programID, offset, "play", { + if (this.player.ads?.scheduledAdBreaks.some((adBreak) => adBreak.timeOffset === 0)) return; + const offset = this.player.currentTime < 0.5 ? 0 : this.player.currentTime; + this.gemiusPlayer.programEvent(programID, offset, 'play', { autoPlay: this.player.autoplay, partID: this.partCount, // resolution: `AxB`; TODO volume: computedVolume, programDuration: this.programParameters.programDuration - }) + }); } - } + }; private onWaiting = (event: WaitingEvent) => { Logger.log(event); - this.reportBasicEvent(BasicEvent.BUFFER) - } + this.reportBasicEvent(BasicEvent.BUFFER); + }; private onSeeking = (event: SeekingEvent) => { Logger.log(event); - this.reportBasicEvent(BasicEvent.SEEK) - } + this.reportBasicEvent(BasicEvent.SEEK); + }; private onEnded = (event: EndedEvent) => { Logger.log(event); - this.reportBasicEvent(BasicEvent.COMPLETE) - } + this.reportBasicEvent(BasicEvent.COMPLETE); + }; private onVolumeChange = (event: VolumeChangeEvent) => { Logger.log(event); - const { volume } = event - const { programID } = this.programParameters - const computedVolume = this.player.muted ? -1 : (volume * 100) + const { volume } = event; + const { programID } = this.programParameters; + const computedVolume = this.player.muted ? -1 : volume * 100; if (this.currentAd) { const { id, adBreak } = this.currentAd; - const { timeOffset } = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) - this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, "chngVol", { volume: computedVolume }); // TODO make SSAI ready + const { timeOffset } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); + this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, 'chngVol', { + volume: computedVolume + }); // TODO make SSAI ready } else { - const { currentTime } = this.player - this.gemiusPlayer.programEvent(programID, currentTime, "chngVol", { volume: computedVolume}) + const { currentTime } = this.player; + this.gemiusPlayer.programEvent(programID, currentTime, 'chngVol', { volume: computedVolume }); } - } + }; private onAddTrack = (event: AddTrackEvent) => { const videoTrack = event.track as MediaTrack; - videoTrack.addEventListener('activequalitychanged', this.onActiveQualityChanged) - } + videoTrack.addEventListener('activequalitychanged', this.onActiveQualityChanged); + }; private onRemoveTrack = (event: RemoveTrackEvent) => { const videoTrack = event.track as MediaTrack; - videoTrack.removeEventListener('activequalitychanged',this.onActiveQualityChanged) - } + videoTrack.removeEventListener('activequalitychanged', this.onActiveQualityChanged); + }; - private onActiveQualityChanged = (event: QualityEvent<"activequalitychanged">) => { - Logger.log(event) + private onActiveQualityChanged = (event: QualityEvent<'activequalitychanged'>) => { + Logger.log(event); const { quality } = event; - const videoQuality = quality as VideoQuality - const { width, height } = videoQuality - const { programID } = this.programParameters - const { currentTime } = this.player - this.gemiusPlayer.programEvent(programID, currentTime, "chngQual", { quality: `${width}x${height}` }); - - } + const videoQuality = quality as VideoQuality; + const { width, height } = videoQuality; + const { programID } = this.programParameters; + const { currentTime } = this.player; + this.gemiusPlayer.programEvent(programID, currentTime, 'chngQual', { quality: `${width}x${height}` }); + }; private onAdBreakBegin = (event: AdBreakEvent<'adbreakbegin'>) => { Logger.log(event); - const { programID } = this.programParameters - const { adBreak } = event - const { timeOffset } = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) - this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, "break"); - this.player.removeEventListener('playing',this.onFirstPlaying); - this.player.addEventListener('playing',this.onFirstPlaying); - } + const { programID } = this.programParameters; + const { adBreak } = event; + const { timeOffset } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); + this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, 'break'); + this.player.removeEventListener('playing', this.onFirstPlaying); + this.player.addEventListener('playing', this.onFirstPlaying); + }; private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { Logger.log(event); this.adCount = 1; const { adBreak } = event; const { timeOffset } = adBreak; - if (!this.isPreRoll(adBreak) )this.partCount++ - const { programID, customAttributes, ...additionalParameters } = this.programParameters - this.gemiusPlayer.newProgram(programID, {...additionalParameters, ...customAttributes}) - this.player.removeEventListener('playing',this.onFirstPlaying); - if (timeOffset === 0) this.player.addEventListener('playing',this.onFirstPlaying); - } + if (!this.isPreRoll(adBreak)) this.partCount++; + const { programID, customAttributes, ...additionalParameters } = this.programParameters; + this.gemiusPlayer.newProgram(programID, { ...additionalParameters, ...customAttributes }); + this.player.removeEventListener('playing', this.onFirstPlaying); + if (timeOffset === 0) this.player.addEventListener('playing', this.onFirstPlaying); + }; private onAdBegin = (event: AdEvent<'adbegin'>) => { Logger.log(event); const { ad } = event; - this.currentAd = ad - const { id, duration, width, height } = ad + this.currentAd = ad; + const { id, duration, width, height } = ad; const { clientWidth, clientHeight } = this.player.element; this.gemiusPlayer.newAd(id ?? DEFAULT_AD_ID, { - adName: ad.integration?.includes("google") ? (ad as GoogleImaAd).title ?? "" : "", + adName: ad.integration?.includes('google') ? (ad as GoogleImaAd).title ?? '' : '', adDuration: duration, adType: AdType.BREAK, // TODO campaignClassification adFormat: 1, quality: `${width}x${height}`, resolution: `${clientWidth}x${clientHeight}`, - volume: this.player.muted ? -1 : (this.player.volume * 100) - }) - } - + volume: this.player.muted ? -1 : this.player.volume * 100 + }); + }; private onAdEnd = (event: AdEvent<'adend'>) => { Logger.log(event); - const { programID } = this.programParameters - const { ad } = event + const { programID } = this.programParameters; + const { ad } = event; const { adBreak } = ad; - const { timeOffset} = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) + const { timeOffset } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); this.gemiusPlayer.adEvent(programID, ad.id ?? DEFAULT_AD_ID, normalizedTimeOffset, BasicEvent.COMPLETE); this.gemiusPlayer.adEvent(programID, ad.id ?? DEFAULT_AD_ID, normalizedTimeOffset, BasicEvent.CLOSE); - this.adCount++ + this.adCount++; this.currentAd = undefined; - this.player.removeEventListener('playing',this.onFirstPlaying); - this.player.addEventListener('playing',this.onFirstPlaying); - } + this.player.removeEventListener('playing', this.onFirstPlaying); + this.player.addEventListener('playing', this.onFirstPlaying); + }; private onAdSkip = (event: AdSkipEvent) => { Logger.log(event); - const { programID } = this.programParameters - const { ad } = event - const { adBreak } = ad - const { timeOffset} = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) + const { programID } = this.programParameters; + const { ad } = event; + const { adBreak } = ad; + const { timeOffset } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); this.gemiusPlayer.programEvent(programID, normalizedTimeOffset, BasicEvent.SKIP); - } - + }; private reportBasicEvent = (event: BasicEvent) => { const { programID } = this.programParameters; const { currentTime } = this.player; if (this.currentAd) { const { id, adBreak } = this.currentAd; - const { timeOffset } = adBreak - const normalizedTimeOffset = this.normalizeTime(timeOffset) + const { timeOffset } = adBreak; + const normalizedTimeOffset = this.normalizeTime(timeOffset); this.gemiusPlayer.adEvent(programID, id ?? DEFAULT_AD_ID, normalizedTimeOffset, event); // TODO make SSAI ready - } + } if (!this.currentAd && event !== BasicEvent.PAUSE) { - this.gemiusPlayer.programEvent(programID,currentTime, event) + this.gemiusPlayer.programEvent(programID, currentTime, event); } - } + }; private normalizeTime = (time: number) => { return this.player.ads?.dai?.contentTimeForStreamTime(time) ?? time; - } + }; private isPreRoll = (adBreak: AdBreak) => { - return adBreak.timeOffset === 0 - } - + return adBreak.timeOffset === 0; + }; } diff --git a/gemius/src/utils/Logger.ts b/gemius/src/utils/Logger.ts index 37448671..3b7ba164 100644 --- a/gemius/src/utils/Logger.ts +++ b/gemius/src/utils/Logger.ts @@ -1,10 +1,9 @@ -import { Event } from "theoplayer"; +import { Event } from 'theoplayer'; const LOG_THEOPLAYER_EVENTS = true; export class Logger { static log = (event: Event) => { - if (LOG_THEOPLAYER_EVENTS) - console.log(`[GEMIUS - THEOplayer EVENTS] ${event.type} event`); - } -} \ No newline at end of file + if (LOG_THEOPLAYER_EVENTS) console.log(`[GEMIUS - THEOplayer EVENTS] ${event.type} event`); + }; +} From 0326f1744cb625f4e96b6c253b2140ecf6b5c1a7 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:27:11 +0200 Subject: [PATCH 44/52] Remove comment --- gemius/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/gemius/src/index.ts b/gemius/src/index.ts index 3a86c818..7a0ac3e9 100644 --- a/gemius/src/index.ts +++ b/gemius/src/index.ts @@ -1,3 +1,2 @@ export { GemiusConnector } from './integration/GemiusConnector'; export * from './integration/GemiusConfiguration'; -// export * from './api/path/to/typing/helpers/etc'; From bc51b2c882e34e86581623cba1066ff4858a0a07 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:30:08 +0200 Subject: [PATCH 45/52] Tweak --- gemius/src/integration/GemiusTHEOIntegration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 2e4f872f..6e0b0ac2 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -108,12 +108,11 @@ export class GemiusTHEOIntegration { console.log(`[GEMIUS] No program parameters were provdided`); return; } + this.reportBasicEvent(BasicEvent.CLOSE); if (!event.source) { // TODO handle some clear source flow - this.reportBasicEvent(BasicEvent.CLOSE); return; } - this.reportBasicEvent(BasicEvent.CLOSE); this.partCount = 1; this.currentAd = undefined; From 15461fe08413e5a3c6d62561471611b5d3f5be67 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:30:14 +0200 Subject: [PATCH 46/52] Rename --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 6e0b0ac2..56d0536f 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -27,7 +27,7 @@ import { Logger } from '../utils/Logger'; import { BasicEvent } from './GemiusEvents'; const THEOPLAYER_ID = 'THEOplayer'; -const DEFAULT_AD_ID = 'PLACEHOLDER ID'; +const DEFAULT_AD_ID = 'PLACEHOLDER_ID'; export class GemiusTHEOIntegration { // References for constructor arguments From a3b96300e46675d69149cbeef053615b1edd35c4 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:30:29 +0200 Subject: [PATCH 47/52] Fix cleanup --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 56d0536f..5e601c92 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -94,7 +94,7 @@ export class GemiusTHEOIntegration { this.player.videoTracks.removeEventListener('removetrack', this.onRemoveTrack); if (this.player.ads) { this.player.ads.removeEventListener('adbreakbegin', this.onAdBreakBegin); - this.player.ads.addEventListener('adbreakend', this.onAdBreakEnd); + this.player.ads.removeEventListener('adbreakend', this.onAdBreakEnd); this.player.ads.removeEventListener('adbegin', this.onAdBegin); this.player.ads.removeEventListener('adend', this.onAdEnd); this.player.ads.removeEventListener('adskip', this.onAdSkip); From cbee49bfa3e8b11528df3a7220cfc53730087031 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:32:06 +0200 Subject: [PATCH 48/52] Remove comments --- gemius/src/integration/GemiusTHEOIntegration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index 5e601c92..b71c92ea 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -30,7 +30,6 @@ const THEOPLAYER_ID = 'THEOplayer'; const DEFAULT_AD_ID = 'PLACEHOLDER_ID'; export class GemiusTHEOIntegration { - // References for constructor arguments private player: ChromelessPlayer; private debug: boolean; private gemiusPlayer: GemiusPlayer; @@ -101,7 +100,6 @@ export class GemiusTHEOIntegration { } } - // EVENT HANDLERS private onSourceChange = (event: SourceChangeEvent) => { Logger.log(event); if (!this.programParameters) { From 24235169161e17fb1d50f3decc6eff9b389b8742 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:34:41 +0200 Subject: [PATCH 49/52] Align logger with other connectors --- .../src/integration/GemiusTHEOIntegration.ts | 32 +++++++++---------- gemius/src/utils/Logger.ts | 12 ++++--- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/gemius/src/integration/GemiusTHEOIntegration.ts b/gemius/src/integration/GemiusTHEOIntegration.ts index b71c92ea..bc7bbb6b 100644 --- a/gemius/src/integration/GemiusTHEOIntegration.ts +++ b/gemius/src/integration/GemiusTHEOIntegration.ts @@ -31,7 +31,7 @@ const DEFAULT_AD_ID = 'PLACEHOLDER_ID'; export class GemiusTHEOIntegration { private player: ChromelessPlayer; - private debug: boolean; + private logger: Logger; private gemiusPlayer: GemiusPlayer; private programParameters: GemiusProgramParameters; @@ -45,7 +45,7 @@ export class GemiusTHEOIntegration { programParameters: GemiusProgramParameters ) { this.player = player; - this.debug = configuration.debug ?? false; + this.logger = new Logger(Boolean(configuration.debug)); this.gemiusPlayer = new window.GemiusPlayer(THEOPLAYER_ID, configuration.gemiusID, {}); this.programParameters = programParameters; this.addListeners(); @@ -101,7 +101,7 @@ export class GemiusTHEOIntegration { } private onSourceChange = (event: SourceChangeEvent) => { - Logger.log(event); + this.logger.log(event); if (!this.programParameters) { console.log(`[GEMIUS] No program parameters were provdided`); return; @@ -119,7 +119,7 @@ export class GemiusTHEOIntegration { }; private onFirstPlaying = (event: PlayingEvent) => { - Logger.log(event); + this.logger.log(event); const { programID } = this.programParameters; const computedVolume = this.player.muted ? -1 : this.player.volume * 100; if (this.currentAd) { @@ -149,12 +149,12 @@ export class GemiusTHEOIntegration { }; private onPause = (event: PauseEvent) => { - Logger.log(event); + this.logger.log(event); this.reportBasicEvent(BasicEvent.PAUSE); }; private onPlay = (event: PlayEvent) => { - Logger.log(event); + this.logger.log(event); const { programID } = this.programParameters; const computedVolume = this.player.muted ? -1 : this.player.volume * 100; if (this.currentAd) { @@ -183,22 +183,22 @@ export class GemiusTHEOIntegration { }; private onWaiting = (event: WaitingEvent) => { - Logger.log(event); + this.logger.log(event); this.reportBasicEvent(BasicEvent.BUFFER); }; private onSeeking = (event: SeekingEvent) => { - Logger.log(event); + this.logger.log(event); this.reportBasicEvent(BasicEvent.SEEK); }; private onEnded = (event: EndedEvent) => { - Logger.log(event); + this.logger.log(event); this.reportBasicEvent(BasicEvent.COMPLETE); }; private onVolumeChange = (event: VolumeChangeEvent) => { - Logger.log(event); + this.logger.log(event); const { volume } = event; const { programID } = this.programParameters; const computedVolume = this.player.muted ? -1 : volume * 100; @@ -226,7 +226,7 @@ export class GemiusTHEOIntegration { }; private onActiveQualityChanged = (event: QualityEvent<'activequalitychanged'>) => { - Logger.log(event); + this.logger.log(event); const { quality } = event; const videoQuality = quality as VideoQuality; const { width, height } = videoQuality; @@ -236,7 +236,7 @@ export class GemiusTHEOIntegration { }; private onAdBreakBegin = (event: AdBreakEvent<'adbreakbegin'>) => { - Logger.log(event); + this.logger.log(event); const { programID } = this.programParameters; const { adBreak } = event; const { timeOffset } = adBreak; @@ -247,7 +247,7 @@ export class GemiusTHEOIntegration { }; private onAdBreakEnd = (event: AdBreakEvent<'adbreakend'>) => { - Logger.log(event); + this.logger.log(event); this.adCount = 1; const { adBreak } = event; const { timeOffset } = adBreak; @@ -259,7 +259,7 @@ export class GemiusTHEOIntegration { }; private onAdBegin = (event: AdEvent<'adbegin'>) => { - Logger.log(event); + this.logger.log(event); const { ad } = event; this.currentAd = ad; const { id, duration, width, height } = ad; @@ -277,7 +277,7 @@ export class GemiusTHEOIntegration { }; private onAdEnd = (event: AdEvent<'adend'>) => { - Logger.log(event); + this.logger.log(event); const { programID } = this.programParameters; const { ad } = event; const { adBreak } = ad; @@ -292,7 +292,7 @@ export class GemiusTHEOIntegration { }; private onAdSkip = (event: AdSkipEvent) => { - Logger.log(event); + this.logger.log(event); const { programID } = this.programParameters; const { ad } = event; const { adBreak } = ad; diff --git a/gemius/src/utils/Logger.ts b/gemius/src/utils/Logger.ts index 3b7ba164..b5c01ef3 100644 --- a/gemius/src/utils/Logger.ts +++ b/gemius/src/utils/Logger.ts @@ -1,9 +1,13 @@ import { Event } from 'theoplayer'; -const LOG_THEOPLAYER_EVENTS = true; - export class Logger { - static log = (event: Event) => { - if (LOG_THEOPLAYER_EVENTS) console.log(`[GEMIUS - THEOplayer EVENTS] ${event.type} event`); + private readonly debug: boolean; + + constructor(debug: boolean = false) { + this.debug = debug; + } + + log = (event: Event) => { + if (this.debug) console.log(`[GEMIUS - THEOplayer EVENTS] ${event.type} event`); }; } From c2c89b92ae6462eadc4b8d5abc53f6685bbda7c4 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:36:30 +0200 Subject: [PATCH 50/52] Add export --- gemius/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gemius/src/index.ts b/gemius/src/index.ts index 7a0ac3e9..09a8e697 100644 --- a/gemius/src/index.ts +++ b/gemius/src/index.ts @@ -1,2 +1,3 @@ export { GemiusConnector } from './integration/GemiusConnector'; export * from './integration/GemiusConfiguration'; +export * from './integration/GemiusParameters'; From 13de6fe60c3e50c06ceaa3f8f1d95d73d0d5cae8 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:39:00 +0200 Subject: [PATCH 51/52] Add te README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e30f04b7..2b8e841d 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Using the available connectors allows you to augment the features delivered thro | 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) | +| Gemius | [![@theoplayer/gemius-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fgemius-connector-web?label=%40theoplayer%2Fgemius-connector-web)](https://npmjs.com/package/@theoplayer/gemius-connector-web) | [gemius](https://github.com/THEOplayer/web-connectors/tree/main/gemius) | | 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) | From fd880be0f8dc67d31989dbc0d4935ebdd4d50c2a Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 9 Aug 2024 15:54:33 +0200 Subject: [PATCH 52/52] Update README & test pages --- gemius/README.md | 88 ++++++++++++++++++++++++++++++--- gemius/test/pages/main_esm.html | 16 +++--- gemius/test/pages/main_umd.html | 17 +++---- 3 files changed, 96 insertions(+), 25 deletions(-) diff --git a/gemius/README.md b/gemius/README.md index ea39bc6e..d164f6ae 100644 --- a/gemius/README.md +++ b/gemius/README.md @@ -11,6 +11,7 @@ npm install @theoplayer/gemius-connector-web Load the gplayer.js library from Gemius. There are two options to to this: either you do it synchronously: ```html + ``` @@ -45,13 +46,88 @@ Department. ## Usage -### Configuring the connector +First you need to add the Gemius connector to your app : + +* Add as a regular script + +```html + + + ``` -## Documentation +* Add as an ES2015 module + +```html + +``` + +## Updating program parameters + +If the program parameters changed during playback, you can update it with: + +```javascript +const newProgramParameters = { ... }; + +gemiusConnector.update(newProgramParameters); +``` diff --git a/gemius/test/pages/main_esm.html b/gemius/test/pages/main_esm.html index b2a63d90..a1242635 100644 --- a/gemius/test/pages/main_esm.html +++ b/gemius/test/pages/main_esm.html @@ -41,20 +41,18 @@ - +