@newrelic/video-core 4.1.8 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -27
- package/dist/cjs/browser/index.js +3 -0
- package/dist/cjs/browser/index.js.LICENSE.txt +6 -0
- package/dist/cjs/browser/index.js.map +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.LICENSE.txt +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/vega/index.js +3 -0
- package/dist/cjs/vega/index.js.LICENSE.txt +6 -0
- package/dist/cjs/vega/index.js.map +1 -0
- package/dist/esm/browser/index.js +3 -0
- package/dist/esm/browser/index.js.LICENSE.txt +6 -0
- package/dist/esm/browser/index.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.LICENSE.txt +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/vega/index.js +3 -0
- package/dist/esm/vega/index.js.LICENSE.txt +6 -0
- package/dist/esm/vega/index.js.map +1 -0
- package/dist/umd/nrvideo.min.js +1 -1
- package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
- package/dist/umd/nrvideo.min.js.map +1 -1
- package/package.json +25 -7
- package/src/{agent.js → browser/agent.js} +14 -35
- package/src/{harvestScheduler.js → browser/harvestScheduler.js} +55 -137
- package/src/browser/index.js +58 -0
- package/src/connectedDevice/connectedDeviceAgent.js +116 -0
- package/src/connectedDevice/connectedDeviceConstants.js +121 -0
- package/src/connectedDevice/connectedDeviceHarvester.js +522 -0
- package/src/connectedDevice/index.js +49 -0
- package/src/constants.js +2 -0
- package/src/core.js +4 -18
- package/src/index.js +9 -10
- package/src/recordEvent.js +56 -49
- package/src/tracker.js +14 -4
- package/src/utils/eventBuilder.js +126 -0
- package/src/utils/harvestTimer.js +109 -0
- package/src/{utils.js → utils/index.js} +2 -2
- package/src/utils/qoeFilters.js +149 -0
- package/src/videoConfiguration.js +56 -10
- package/src/videotracker.js +26 -9
package/README.md
CHANGED
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@newrelic/video-core)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
> **Note:** The `PageAction` event type is officially deprecated and is no longer maintained. It has been archived in the [`archived-master`](https://github.com/newrelic/video-core-js/tree/archived-master) branch for historical reference.
|
|
7
8
|
|
|
8
|
-
The **New Relic Video Core** library (`@newrelic/video-core`) is the foundational framework for
|
|
9
|
+
The **New Relic Video Core** library (`@newrelic/video-core`) is the foundational framework for video trackers in the New Relic ecosystem. It provides the core classes, state management, event harvesting, and data transmission pipeline that player-specific trackers extend. The library supports two harvester pipelines:
|
|
10
|
+
|
|
11
|
+
- **Browser pipeline** — ships events to `bam.nr-data.net` via the standard Browser collector (license key auth). Used by web-based players.
|
|
12
|
+
- **Connected-device pipeline** — ships events to `mobile-collector.newrelic.com` via the mobile collector. Used by Vega apps and other connected-device platforms.
|
|
13
|
+
|
|
9
14
|
|
|
10
15
|
Events are categorized into four distinct types:
|
|
11
16
|
|
|
@@ -95,13 +100,10 @@ class MyPlayerTracker extends nrvideo.VideoTracker {
|
|
|
95
100
|
// 2. Configure and register the tracker
|
|
96
101
|
const options = {
|
|
97
102
|
info: {
|
|
98
|
-
licenseKey:
|
|
99
|
-
beacon:
|
|
103
|
+
licenseKey: 'YOUR_LICENSE_KEY',
|
|
104
|
+
beacon: 'bam.nr-data.net',
|
|
100
105
|
applicationID: 'YOUR_APPLICATION_ID',
|
|
101
106
|
},
|
|
102
|
-
config: {
|
|
103
|
-
qoeAggregate: true,
|
|
104
|
-
},
|
|
105
107
|
};
|
|
106
108
|
|
|
107
109
|
const player = document.getElementById('myPlayer');
|
|
@@ -113,41 +115,39 @@ nrvideo.Core.addTracker(tracker, options);
|
|
|
113
115
|
|
|
114
116
|
## Configuration
|
|
115
117
|
|
|
116
|
-
The `options` object passed to `Core.addTracker()` consists of two
|
|
118
|
+
The `options` object passed to `Core.addTracker()` consists of two top-level keys: `info` (credentials and pipeline config) and `config` (optional behaviour settings).
|
|
117
119
|
|
|
118
|
-
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### Browser / Web Setup
|
|
119
123
|
|
|
120
|
-
|
|
124
|
+
**Obtain your credentials:**
|
|
121
125
|
|
|
122
126
|
1. Log in to [one.newrelic.com](https://one.newrelic.com)
|
|
123
127
|
2. Navigate to the video agent onboarding flow
|
|
124
128
|
3. Copy your credentials: `licenseKey`, `beacon`, and `applicationId`
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Obtained through the New Relic onboarding process. Two configuration modes are supported:
|
|
129
|
-
|
|
130
|
-
**Mode 1 — With Application ID and Beacon:**
|
|
130
|
+
**With Application ID and Beacon:**
|
|
131
131
|
|
|
132
132
|
```javascript
|
|
133
133
|
info: {
|
|
134
|
-
licenseKey:
|
|
135
|
-
applicationID: 'YOUR_APPLICATION_ID',
|
|
136
|
-
beacon:
|
|
134
|
+
licenseKey: 'YOUR_LICENSE_KEY', // Required
|
|
135
|
+
applicationID: 'YOUR_APPLICATION_ID', // Required
|
|
136
|
+
beacon: 'bam.nr-data.net', // Required when applicationID is provided
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
**
|
|
140
|
+
**With App Name and Region:**
|
|
141
141
|
|
|
142
142
|
```javascript
|
|
143
143
|
info: {
|
|
144
144
|
licenseKey: 'YOUR_LICENSE_KEY', // Required
|
|
145
|
-
appName:
|
|
146
|
-
region:
|
|
145
|
+
appName: 'My Video App', // Required when no applicationID
|
|
146
|
+
region: 'US', // Required when no applicationID — 'US' | 'EU' | 'staging'
|
|
147
147
|
}
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
**Valid Beacon Endpoints:**
|
|
150
|
+
**Valid Browser Beacon Endpoints:**
|
|
151
151
|
|
|
152
152
|
| Region | Beacon |
|
|
153
153
|
|---|---|
|
|
@@ -156,11 +156,89 @@ info: {
|
|
|
156
156
|
| Staging | `staging-bam-cell.nr-data.net` |
|
|
157
157
|
| GOV | `gov-bam.nr-data.net` |
|
|
158
158
|
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Vega / Fire TV Setup
|
|
162
|
+
|
|
163
|
+
For Amazon Vega (Fire TV / Kepler runtime), import from the `/vega` subpath. The `info` object uses `applicationToken` and `endpoint` specific to the Vega pipeline, plus an optional `deviceInfo` block carrying runtime device identity.
|
|
164
|
+
|
|
165
|
+
**Obtain your application token:**
|
|
166
|
+
|
|
167
|
+
1. Log in to [one.newrelic.com](https://one.newrelic.com)
|
|
168
|
+
2. Navigate to the video agent onboarding flow
|
|
169
|
+
3. Copy your `applicationToken` (begins with `AA...` and ends with `-NRMA`) and your `accountId`
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
info: {
|
|
173
|
+
accountId: 'YOUR_ACCOUNT_ID', // Required
|
|
174
|
+
applicationToken: 'YOUR_NRMA_TOKEN', // Required — begins "AA…-NRMA"
|
|
175
|
+
endpoint: 'US', // Required — 'US' | 'EU' | 'staging' | 'GOV'
|
|
176
|
+
deviceInfo: { // Optional — all sub-fields optional
|
|
177
|
+
uuid: getDeviceId(),
|
|
178
|
+
osVersion: getSystemVersion(),
|
|
179
|
+
deviceModel: getModel(),
|
|
180
|
+
deviceManufacturer: getBrand(),
|
|
181
|
+
osBuild: getBuildIdSync(),
|
|
182
|
+
appBuild: getBuildNumber(),
|
|
183
|
+
architecture: 'aarch64',
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Install the device-info library to source real device attributes at runtime:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm install @amazon-devices/react-native-device-info --save
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
import {
|
|
196
|
+
getDeviceId, getSystemVersion, getModel, getBrand,
|
|
197
|
+
getBuildIdSync, getBuildNumber,
|
|
198
|
+
} from '@amazon-devices/react-native-device-info';
|
|
199
|
+
|
|
200
|
+
const deviceInfo = {
|
|
201
|
+
uuid: getDeviceId(),
|
|
202
|
+
osVersion: getSystemVersion(),
|
|
203
|
+
deviceModel: getModel(),
|
|
204
|
+
deviceManufacturer: getBrand(),
|
|
205
|
+
osBuild: getBuildIdSync(), // OS image build
|
|
206
|
+
appBuild: getBuildNumber(), // app build number
|
|
207
|
+
architecture: 'aarch64',
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### `deviceInfo` field reference
|
|
212
|
+
|
|
213
|
+
All sub-fields are optional — missing values fall back to the SDK defaults. Extra fields are ignored.
|
|
214
|
+
|
|
215
|
+
| Field | Recommended source | Falls back to |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `uuid` | `getDeviceId()` — stable model-code identifier | `"00000000-0000-0000-0000-000000000000"` |
|
|
218
|
+
| `osVersion` | `getSystemVersion()` | `"1.0"` |
|
|
219
|
+
| `deviceModel` | `getModel()` | `"VegaDevice"` |
|
|
220
|
+
| `deviceManufacturer` | `getBrand()` | `"Amazon"` |
|
|
221
|
+
| `osBuild` | `getBuildIdSync()` — **OS image build** | `"1"` |
|
|
222
|
+
| `appBuild` | `getBuildNumber()` — **app build number** | `"1"` |
|
|
223
|
+
| `architecture` | `'aarch64'` | `"aarch64"` |
|
|
224
|
+
|
|
225
|
+
> `osBuild` and `appBuild` are semantically distinct: `osBuild` is the OS image identifier set by Amazon; `appBuild` is your app's build number. Use `getBuildIdSync()` for the former and `getBuildNumber()` for the latter.
|
|
226
|
+
|
|
227
|
+
**Valid Vega Endpoints:**
|
|
228
|
+
|
|
229
|
+
| Value | Routes to |
|
|
230
|
+
|---|---|
|
|
231
|
+
| `'US'` | `mobile-collector.newrelic.com` |
|
|
232
|
+
| `'EU'` | `mobile-collector.eu01.nr-data.net` |
|
|
233
|
+
| `'staging'` | `staging-mobile-collector.newrelic.com` |
|
|
234
|
+
| `'GOV'` | `gov-mobile-collector.newrelic.com` |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
159
238
|
### Config Object (Optional)
|
|
160
239
|
|
|
161
240
|
| Option | Type | Default | Description |
|
|
162
241
|
|---|---|---|---|
|
|
163
|
-
| `qoeAggregate` | `boolean` | `true` | Enable Quality of Experience event aggregation. QoE is enabled out of the box; set to `false` to disable. |
|
|
164
242
|
| `qoeIntervalFactor` | `number` | `2` | Include QoE aggregate events once every N harvest cycles. Must be a positive integer. QoE events are always sent on the first and final harvest cycles. |
|
|
165
243
|
| `obfuscate` | `array` | `[]` | Regex-based rules to mask sensitive data before transmission. See [Obfuscation Rules](#obfuscation-rules). |
|
|
166
244
|
|
|
@@ -192,7 +270,6 @@ Static class managing tracker registration and event dispatch.
|
|
|
192
270
|
| `Core.getTrackers()` | Returns the array of currently registered trackers. |
|
|
193
271
|
| `Core.send(eventType, actionName, data)` | Sends an event to the collector. Called internally by event handlers. |
|
|
194
272
|
| `Core.sendError(att)` | Sends a `VideoErrorAction` with `actionName: "ERROR"`. For external/app-level errors. |
|
|
195
|
-
| `Core.forceHarvest()` | Forces an immediate harvest of all pending events. Returns a `Promise`. |
|
|
196
273
|
|
|
197
274
|
### VideoTracker
|
|
198
275
|
|
|
@@ -308,15 +385,32 @@ nrvideo.Log.level = nrvideo.Log.Levels.DEBUG; // ALL, DEBUG, NOTICE, WARNING, ER
|
|
|
308
385
|
|
|
309
386
|
### Constants
|
|
310
387
|
|
|
388
|
+
**General constants** (used by both pipelines):
|
|
389
|
+
|
|
311
390
|
| Constant | Value | Description |
|
|
312
391
|
|---|---|---|
|
|
313
392
|
| `Constants.AdPositions` | `{ PRE, MID, POST }` | Ad position enum. |
|
|
314
|
-
| `Constants.COLLECTOR` | Object |
|
|
393
|
+
| `Constants.COLLECTOR` | Object | Browser beacon endpoint URLs by region. |
|
|
315
394
|
| `Constants.VALID_EVENT_TYPES` | Array | `['VideoAction', 'VideoAdAction', 'VideoErrorAction', 'VideoCustomAction']` |
|
|
316
395
|
| `Constants.MAX_PAYLOAD_SIZE` | `1048576` | Maximum payload size (1 MB). |
|
|
317
396
|
| `Constants.MAX_BEACON_SIZE` | `61440` | Maximum beacon size (60 KB). |
|
|
318
397
|
| `Constants.MAX_EVENTS_PER_BATCH` | `1000` | Maximum events per batch. |
|
|
319
398
|
| `Constants.INTERVAL` | `10000` | Default harvest interval (10s). |
|
|
399
|
+
| `Constants.QOE_KPI_KEYS` | Array | KPI field names tracked in QoE aggregates. |
|
|
400
|
+
| `Constants.QOE_AGGREGATE_KEYS` | Array | Metadata field names included in QoE events. |
|
|
401
|
+
|
|
402
|
+
**Connected-device constants** (named exports from `constants.js`, used by the `/vega` subpath):
|
|
403
|
+
|
|
404
|
+
| Export | Description |
|
|
405
|
+
|---|---|
|
|
406
|
+
| `MOBILE_ENDPOINT` | Production mobile collector URL (`mobile-collector.newrelic.com`). |
|
|
407
|
+
| `STAGING_MOBILE_ENDPOINT` | Staging mobile collector URL. |
|
|
408
|
+
| `NR_ENDPOINT` | Endpoint region enum: `{ US, EU, STAGING }`. |
|
|
409
|
+
| `DEFAULT_HARVEST_TIME` | Default harvest cadence: `60_000` ms. |
|
|
410
|
+
| `DEFAULT_BUFFER_SIZE` | Default buffer cap: `100` events (informational). |
|
|
411
|
+
| `CD_DATA_TOKENS_PAYLOAD` | `/v5/connect` request body template (positional 2-tuple). |
|
|
412
|
+
| `CD_DEVICE_INFO` | `/v3/data` device-identity tuple (default Vega values). |
|
|
413
|
+
| `CD_METADATA` | `/v3/data` session-metadata object (default Vega values). |
|
|
320
414
|
|
|
321
415
|
---
|
|
322
416
|
|
|
@@ -474,13 +568,32 @@ npm run clean
|
|
|
474
568
|
|
|
475
569
|
## Distribution Formats
|
|
476
570
|
|
|
477
|
-
The build produces
|
|
571
|
+
The build produces multiple output formats including subpath exports for tree-shaking:
|
|
478
572
|
|
|
479
573
|
| Format | Path | Usage |
|
|
480
574
|
|---|---|---|
|
|
481
575
|
| **UMD** | `dist/umd/nrvideo.min.js` | `<script>` tag → `window.nrvideo` |
|
|
482
|
-
| **CommonJS** | `dist/cjs/index.js` | `require('@newrelic/video-core')` |
|
|
483
|
-
| **ES Module** | `dist/esm/index.js` | `import nrvideo from '@newrelic/video-core'` |
|
|
576
|
+
| **CommonJS** | `dist/cjs/index.js` | `require('@newrelic/video-core')` — both pipelines |
|
|
577
|
+
| **ES Module** | `dist/esm/index.js` | `import nrvideo from '@newrelic/video-core'` — both pipelines |
|
|
578
|
+
| **CJS Browser** | `dist/cjs/browser/index.js` | `require('@newrelic/video-core/browser')` — Browser pipeline only |
|
|
579
|
+
| **CJS Connected-Device** | `dist/cjs/vega/index.js` | `require('@newrelic/video-core/vega')` — connected-device pipeline only |
|
|
580
|
+
| **ESM Browser** | `dist/esm/browser/index.js` | `import ... from '@newrelic/video-core/browser'` |
|
|
581
|
+
| **ESM Connected-Device** | `dist/esm/vega/index.js` | `import ... from '@newrelic/video-core/vega'` |
|
|
582
|
+
|
|
583
|
+
### Subpath imports
|
|
584
|
+
|
|
585
|
+
Import the specific subpath to ship only the harvester chain you need. The unused pipeline is tree-shaken from the bundle.
|
|
586
|
+
|
|
587
|
+
```javascript
|
|
588
|
+
// Browser pipeline only — tree-shakes out the connected-device chain
|
|
589
|
+
import nrvideo from '@newrelic/video-core/browser';
|
|
590
|
+
|
|
591
|
+
// Connected-device pipeline only — tree-shakes out Browser harvester and harvestScheduler
|
|
592
|
+
import nrvideo from '@newrelic/video-core/vega';
|
|
593
|
+
|
|
594
|
+
// Both pipelines — use with the default entry
|
|
595
|
+
import nrvideo from '@newrelic/video-core';
|
|
596
|
+
```
|
|
484
597
|
|
|
485
598
|
## Testing
|
|
486
599
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
+
(()=>{"use strict";const t={d:(e,i)=>{if(Array.isArray(i))for(var s=0;s<i.length;){var r=i[s++],a=i[s++];t.o(e,r)?0===a&&s++:0===a?Object.defineProperty(e,r,{enumerable:!0,value:i[s++]}):Object.defineProperty(e,r,{enumerable:!0,get:a})}else for(var r in i)t.o(i,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:i[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}};let e={};t.r(e),t.d(e,{Chrono:()=>u,Constants:()=>h,Core:()=>w,Emitter:()=>l,HarvestScheduler:()=>q,Log:()=>n,NrVideoEventAggregator:()=>P,OptimizedHttpClient:()=>F,RetryQueueHandler:()=>H,Tracker:()=>m,VideoTracker:()=>C,VideoTrackerState:()=>D,default:()=>M,getRegisteredHarvester:()=>p,recordEvent:()=>v,version:()=>d.rE,videoAnalyticsHarvester:()=>G});class i{static error(...t){s(t,i.Levels.ERROR,"darkred")}static warn(...t){s(t,i.Levels.WARNING,"darkorange")}static notice(...t){s([].slice.call(arguments),i.Levels.NOTICE,"darkcyan")}static debug(...t){s(t,i.Levels.DEBUG,"indigo")}static debugCommonVideoEvents(t,e,s){try{if(i.level<=i.Levels.DEBUG){s=s||function(t){i.debug("Event: "+t.type)};var r=["canplay","buffering","waiting","ended","play","playing","pause","resume","error","abort","seek","seeking","seeked","stalled","dispose","loadeddata","loadstart","loadedmetadata"];e&&(null===e[0]?(e.shift(),r=e):r=r.concat(e));for(var a=0;a<r.length;a++)"function"==typeof t?t.call(window,r[a],s):t.on?t.on(r[a],s):t.addEventListener?t.addEventListener(r[a],s):t.addEventHandler?t.addEventHandler(r[a],s):i.warn("debugCommonVideoEvents: No common listener function found for ",t)}}catch(t){i.warn(t)}}}function s(t,e,s){e=e||i.Levels.NOTICE,s=s||"darkcyan";var n,o,h,d,l,c,u=i.prefix;(i.includeTime&&(u+=(n=new Date,o=("0"+n.getDate()).slice(-2),h=("0"+n.getMinutes()).slice(-2),d=("0"+n.getSeconds()).slice(-2),l=("00"+n.getMilliseconds()).slice(-3),"["+o+":"+h+":"+d+"."+l+"] ")),u+=function(t){return a[t]}(e)+":",i.level<=e&&e!==i.Levels.SILENT)&&(!i.colorful||"undefined"!=typeof document&&document.documentMode?r(t,u):(c=e===i.Levels.ERROR&&console.error?console.error:e===i.Levels.WARNING&&console.warn?console.warn:e===i.Levels.DEBUG&&console.debug&&null==window.cast?console.debug:console.log,u="%c"+u,t.splice(0,0,u,"color: "+s),c.apply(console,t)))}function r(t,e){if(t instanceof Array)for(var i in t)r(t[i],e);else"string"==typeof t?console.log(e+" "+t):(console.log(e+"↵"),console.log(t))}i.Levels={SILENT:5,ERROR:4,WARNING:3,NOTICE:2,DEBUG:1,ALL:0},i.level=i.Levels.ERROR,i.colorful=!0,i.includeTime=!0,i.prefix="[nrvideo]";const a={4:"e",3:"w",2:"n",1:"d"};!function(){if("undefined"!=typeof window&&window.location&&window.location.search){var t=/\?.*&*nrvideo-debug=(.+)/i.exec(window.location.search);null!==t&&("true"===t[1]?i.level=i.Levels.ALL:i.level=t[1]),null!==/\?.*&*nrvideo-colors=false/i.exec(window.location.search)&&(i.colorful=!1)}}();const n=i;class o{}o.AdPositions={PRE:"pre",MID:"mid",POST:"post"},o.COLLECTOR={US:["bam.nr-data.net","bam-cell.nr-data.net"],EU:"bam.eu01.nr-data.net",JP:"bam.jp.nr-data.net",Staging:"staging-bam-cell.nr-data.net",GOV:"gov-bam.nr-data.net"},o.VALID_EVENT_TYPES=["VideoAction","VideoAdAction","VideoErrorAction","VideoCustomAction"],o.MAX_PAYLOAD_SIZE=1048576,o.MAX_BEACON_SIZE=61440,o.MAX_EVENTS_PER_BATCH=1e3,o.INTERVAL=1e4,o.DEFAULT_QOE_INTERVAL_FACTOR=2,o.QOE_KPI_KEYS=["startupTime","peakBitrate","averageBitrate","totalPlaytime","totalRebufferingTime","rebufferingRatio","hadStartupError","hadPlaybackError","numberOfErrors"],o.QOE_AGGREGATE_KEYS=["coreVersion","instrumentation.name","instrumentation.provider","instrumentation.version","isBackgroundEvent","playerName","playerVersion","src","viewId","viewSession","contentIsAutoplayed","contentIsMuted","contentRenditionHeight","contentRenditionWidth","contentSrc","numberOfVideos","pageUrl","trackerName","trackerVersion","contentDuration","contentPlayrate","contentPlayhead","contentPreload","elapsedTime","contentTitle","contentId","contentIsLive","deviceType","deviceGroup","deviceManufacturer","deviceModel","deviceName","deviceSize","deviceUuid","contentRenditionName","contentIsFullscreen","contentCdn","contentFps","asnOrganization","asnLongitude","asnLatitude","asn","timeSinceRequested","timeSinceStarted"];const h=o,d={rE:"5.0.0"};const l=class{on(t,e){if(this._listeners=this._listeners||{},"function"==typeof e)return this._listeners[t]=this._listeners[t]||[],this._listeners[t].push(e),this}off(t,e){if(this._listeners=this._listeners||{},this._listeners[t]){var i=this._listeners[t].indexOf(e);-1!==i&&this._listeners[t].splice(i,1)}return this}emit(t,e,i){return this._listeners=this._listeners||{},i=i||{},Array.isArray(this._listeners[e])&&this._listeners[e].forEach(s=>{s.call(this,{eventType:t,type:e,data:i,target:this})}),Array.isArray(this._listeners["*"])&&this._listeners["*"].forEach(s=>{s.call(this,{eventType:t,type:e,data:i,target:this})}),this}};class c{constructor(){this.reset()}reset(){this.startTime=0,this.stopTime=0,this.accumulator=0,this.offset=0}getDeltaTime(){return this.startTime?this.offset+((new Date).getTime()-this.startTime):null}start(){this.startTime=(new Date).getTime(),this.stopTime=0}stop(){return this.stopTime=(new Date).getTime(),this.startTime<this.stopTime&&(this.accumulator+=this.stopTime-this.startTime),this.getDeltaTime()}getDuration(){return this.stopTime?this.accumulator+this.offset:this.accumulator+(this.getDeltaTime()??0)}clone(){var t=new c;return t.startTime=this.startTime,t.stopTime=this.stopTime,t.offset=this.offset,t.accumulator=this.accumulator,t}}const u=c;class g extends l{constructor(t){super(),this.customData={},this.heartbeat=null,this.parentTracker=null,this._trackerReadyChrono=new u,this._trackerReadyChrono.start(),this._actionTable=h.ACTION_TABLE,this._actionAdTable=h.ACTION_AD_TABLE,t=t||{},this.setOptions(t)}setOptions(t){t&&(t.parentTracker&&(this.parentTracker=t.parentTracker),t.customData&&(this.customData=t.customData),t.heartbeat&&(this.heartbeat=t.heartbeat))}dispose(){this.unregisterListeners()}registerListeners(){}unregisterListeners(){}getHeartbeat(){return this.state._isAd?2e3:this.heartbeat?this.heartbeat:this.parentTracker&&this.parentTracker.heartbeat?this.parentTracker.heartbeat:3e4}startHeartbeat(){this._heartbeatInterval=setInterval(this.sendHeartbeat.bind(this),Math.max(this.getHeartbeat(),2e3))}stopHeartbeat(){this._heartbeatInterval&&clearInterval(this._heartbeatInterval)}sendHeartbeat(t){this.sendVideoAction(g.Events.HEARTBEAT,t)}getAttributes(t,e){(t=t||{}).trackerName=this.getTrackerName(),t.trackerVersion=this.getTrackerVersion(),t.coreVersion=d.rE,t.timeSinceTrackerReady=this._trackerReadyChrono.getDeltaTime();for(let e in this.customData)t[e]=this.customData[e];return null!=document.hidden&&(t.isBackgroundEvent=document.hidden),t}getTrackerVersion(){return d.rE}getTrackerName(){return"base-tracker"}sendVideoAction(t,e){this.emit("VideoAction",t,this.getAttributes(e))}sendVideoAdAction(t,e){this.emit("VideoAdAction",t,this.getAttributes(e))}sendVideoErrorAction(t,e){let i=this.isAd()?"adError":"videoError";this.emit("VideoErrorAction",t,this.getAttributes(e,i))}sendVideoCustomAction(t,e){this.emit("VideoCustomAction",t,this.getAttributes(e,"customAction"))}setHarvestInterval(t){const e=this.getHarvester?.();if(e)try{e.setHarvestInterval(t)}catch(t){return void n.error("Failed to set harvest interval:",t.message)}else n.error("Tracker has no harvester; setHarvestInterval ignored")}getHarvester(){return null}}g.Events={HEARTBEAT:"HEARTBEAT",QOE_AGGREGATE:"QOE_AGGREGATE"};const m=g;function f(t){try{return JSON.stringify(t,(()=>{const t=new WeakSet;return(e,i)=>{if("object"==typeof i&&null!==i){if(t.has(i))return;t.add(i)}return i}})())??""}catch(t){return n.error("Error stringifying value:",t.message),""}}function E(t){if("string"==typeof t&&t.length)return t.length;if("object"==typeof t){if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer&&t.byteLength)return t.byteLength;if("undefined"!=typeof Blob&&t instanceof Blob&&t.size)return t.size;if(!("undefined"!=typeof FormData&&t instanceof FormData))try{return f(t).length}catch(t){return}}}function A(t,e,i,{addTimeSinceLoad:s=!1}={}){const{appName:r,applicationID:a}=i,{qoe:n,...o}=e,d=n?{...n}:{},l={...a?{}:{appName:r},timestamp:Date.now(),...s?{timeSinceLoad:"undefined"!=typeof window&&window.performance?window.performance.now()/1e3:null}:{}},c={...o,eventType:t,...l};let u=null;if("VideoAction"===t){const t=(g=h.QOE_AGGREGATE_KEYS,f=e,g&&Array.isArray(g)&&0!==g.length?f&&"object"==typeof f?g.reduce((t,e)=>(e in f&&(t[e]=f[e]),t),{}):{}:f);u={eventType:"VideoAction",actionName:m.Events.QOE_AGGREGATE,qoeAggregateVersion:"1.0.0",...d,...t,...l}}var g,f;return{eventObject:c,qoeEventObject:u}}const T=Object.create(null);function p(t){return T[t]}function v(t,e={}){try{if(!h.VALID_EVENT_TYPES.includes(t))return n.warn("Invalid event type provided to recordEvent",{eventType:t}),!1;const i="Vega"===e.src,s=i?"Vega":"Browser",r="undefined"!=typeof window?window:void 0,a=i?globalThis.__NRVIDEO_CD__?.info:r?.NRVIDEO?.info;if(!a)return;const o=T[s];if(!o)return n.warn("No harvester registered for routing key",{routingKey:s}),!1;return function(t,e,i,s,r,{addTimeSinceLoad:a=!1}={}){if(!s)return!1;const{eventObject:n,qoeEventObject:o}=A(t,e,i,{addTimeSinceLoad:a}),h=s.addEvent(n);return o&&r?h&&s.addEvent(o):h}(t,e,a,o,i?globalThis.__NRVIDEO_CD__?.config?.qoeAggregate:r?.NRVIDEO?.config?.qoeAggregate,{addTimeSinceLoad:!i})}catch(t){return n.error("Failed to record event:",t.message),!1}}const{COLLECTOR:S}=h;class y{setConfiguration(t,e,i){return!!("Vega"===i?this.validateVegaFields(t):this.validateRequiredFields(t))&&(!!this.validateConfigFields(e)&&(this.initializeGlobalConfig(t,e,i),n.notice("Video analytics configuration initialized successfully"),!0))}validateVegaFields(t){return t&&"object"==typeof t?t.applicationToken?!!["US","EU","staging","GOV"].includes(t.endpoint)||(n.error("Invalid endpoint (must be US, EU, staging, or GOV)"),!1):(n.error("applicationToken is required"),!1):(n.error("Configuration must be an object"),!1)}validateRequiredFields(t){if(!t||"object"!=typeof t)return n.error("Configuration must be an object"),!1;const{licenseKey:e,appName:i,region:s,applicationID:r,beacon:a}=t;if(!e)return n.error("licenseKey is required"),!1;if(r){if(!a)return n.error("beacon is required when applicationID is provided"),!1;if(!Object.values(S).flatMap(t=>t).includes(a))return n.error(`Invalid beacon: ${a}`),!1}else{if(!i||!s)return n.error("appName and region are required when applicationID is not provided"),!1;if(!S[s])return n.error(`Invalid region: ${s}. Valid regions are: ${Object.keys(S).join(", ")}`),!1}return!0}validateConfigFields(t){if(null==t)return!0;if("object"!=typeof t||Array.isArray(t))return n.error("config must be an object"),!1;const{qoeAggregate:e,obfuscate:i}=t;return void 0!==e&&"boolean"!=typeof e?(n.error("qoeAggregate must be a boolean"),!1):!(void 0!==i&&!Array.isArray(i))||(n.error("obfuscate must be an array"),!1)}filterObfuscateRules(t){return t?t.filter(t=>{const e=void 0!==t.regex&&("string"==typeof t.regex||t.regex instanceof RegExp),i=void 0!==t.replacement&&"string"==typeof t.replacement;return!(!e||!i)||(n.warn("obfuscate rule missing required 'regex' (string|RegExp) and/or 'replacement' (string), skipping:",t),!1)}):[]}sanitizeQoeIntervalFactor(t){return null==t?h.DEFAULT_QOE_INTERVAL_FACTOR:"number"==typeof t&&Number.isInteger(t)&&t>=1?t:(n.warn(`Invalid qoeIntervalFactor "${t}" — must be a positive integer. Defaulting to ${h.DEFAULT_QOE_INTERVAL_FACTOR}.`),h.DEFAULT_QOE_INTERVAL_FACTOR)}initializeGlobalConfig(t,e,i){if("Vega"===i)return void(globalThis.__NRVIDEO_CD__={info:{accountId:t.accountId,applicationToken:t.applicationToken,endpoint:t.endpoint,...t.appName?{appName:t.appName}:{},...t.applicationID?{applicationID:t.applicationID}:{},...t.deviceInfo?{deviceInfo:t.deviceInfo}:{}},config:{qoeAggregate:e?.qoeAggregate??!0,qoeIntervalFactor:this.sanitizeQoeIntervalFactor(e?.qoeIntervalFactor),obfuscate:this.filterObfuscateRules(e?.obfuscate)}});let{licenseKey:s,appName:r,region:a,beacon:n,applicationID:o}=t;n="US"===a?h.COLLECTOR.US[0]:n||S[a],window.NRVIDEO={info:{...a?{region:a}:{},beacon:n,licenseKey:s,applicationID:o,...o?{}:{appName:r}},config:{qoeAggregate:e?.qoeAggregate??!0,qoeIntervalFactor:this.sanitizeQoeIntervalFactor(e?.qoeIntervalFactor),obfuscate:this.filterObfuscateRules(e?.obfuscate)}}}}const _=new y;class R{static addTracker(t,e){var i,s,r;e?.info&&(i=e.info,s=e?.config,r=e?.src,_.setConfiguration(i,s,r)),t.on&&t.emit?(B.push(t),t.on("*",b),"function"==typeof t.trackerInit&&t.trackerInit()):n.error("Tried to load a non-tracker.",t)}static removeTracker(t){t.off("*",b),t.dispose();let e=B.indexOf(t);-1!==e&&B.splice(e,1)}static getTrackers(){return B}static send(t,e,i){return v(t,{actionName:e,...i})}static sendError(t){return v("VideoErrorAction",{actionName:"ERROR",...t})}}let B=[];function b(t){try{let e=function(t){let e={};for(let i in t)null!==t[i]&&void 0!==t[i]&&(e[i]=t[i]);return e}(t.data);n.level<=n.Levels.DEBUG?n.notice("Sent",t.type,e):n.notice("Sent",t.type),R.send(t.eventType,t.type,e)}catch(t){n.error("Error in event handler:",t.message)}}const w=R;const D=class{constructor(){this.reset(),this._createdAt=Date.now(),this._hb=!0,this._acc=0,this._bufferAcc=0}reset(){this._viewSession=null,this._viewCount=0,this._isAd=!1,this.numberOfErrors=0,this.numberOfAds=0,this.numberOfVideos=0,this.totalPlaytime=0,this.weightedAverageBitrate=0,this.totalAdPlaytime=0,this.isAdBreak=!1,this.initialBufferingHappened=!1,this.startupTime=null,this.peakBitrate=0,this.partialAverageBitrate=0,this._totalBitrateDuration=0,this.weightedBitrate=0,this._lastBitrate=null,this._lastBitrateChangeTimestamp=null,this._downloadBitrates=[],this._lastDownloadBitrate=null,this.totalSwitchUps=0,this.totalSwitchDowns=0,this.totalPauseTime=0,this._playedRenditions=new Set,this.hadStartupError=!1,this.hadPlaybackError=!1,this.totalRebufferingTime=0,this.resetFlags(),this.resetChronos()}resetFlags(){this.isPlayerReady=!1,this.isRequested=!1,this.isStarted=!1,this.isPaused=!1,this.isSeeking=!1,this.isBuffering=!1,this.isPlaying=!1}resetChronos(){this.timeSinceRequested=new u,this.timeSinceStarted=new u,this.timeSincePaused=new u,this.timeSinceSeekBegin=new u,this.timeSinceBufferBegin=new u,this.timeSinceAdBreakStart=new u,this.timeSinceLastDownload=new u,this.timeSinceLastHeartbeat=new u,this.timeSinceLastRenditionChange=new u,this.timeSinceLastAdQuartile=new u,this.timeSinceLastAd=new u,this.timeSinceLastError=new u,this.timeSinceLastAdError=new u,this.timeSinceResumed=new u,this.timeSinceSeekEnd=new u,this.playtimeSinceLastEvent=new u,this.customTimeSinceAttributes={},this.elapsedTime=new u,this.bufferElapsedTime=new u,this._totalAdPlaytime=new u}isAd(){return this._isAd}setIsAd(t){this._isAd=t}setTimeSinceAttribute(t){this.customTimeSinceAttributes[t]=new u,this.customTimeSinceAttributes[t].start()}removeTimeSinceAttribute(t){delete this.customTimeSinceAttributes[t]}getViewSession(){if(!this._viewSession){let t=(new Date).getTime(),e=Math.random().toString(36).substring(2)+Math.random().toString(36).substring(2);this._viewSession=t+"-"+e}return this._viewSession}getViewId(){return this.getViewSession()+"-"+this._viewCount}getStateAttributes(t){t=t||{},this.isAd()?(this.isRequested&&(t.timeSinceAdRequested=this.timeSinceRequested.getDeltaTime(),t.timeSinceLastAdHeartbeat=this.timeSinceLastHeartbeat.getDeltaTime()),this.isStarted&&(t.timeSinceAdStarted=this.timeSinceStarted.getDeltaTime()),this.isPaused&&(t.timeSinceAdPaused=this.timeSincePaused.getDeltaTime()),this.isBuffering&&(t.timeSinceAdBufferBegin=this.timeSinceBufferBegin.getDeltaTime()),this.isSeeking&&(t.timeSinceAdSeekBegin=this.timeSinceSeekBegin.getDeltaTime()),this.isAdBreak&&(t.timeSinceAdBreakBegin=this.timeSinceAdBreakStart.getDeltaTime()),this.numberOfErrors>0&&this.timeSinceLastAdError.startTime>0&&(t.timeSinceLastAdError=this.timeSinceLastAdError.getDeltaTime()),t.numberOfAds=this.numberOfAds):(this.isRequested&&(t.timeSinceRequested=this.timeSinceRequested.getDeltaTime(),t.timeSinceLastHeartbeat=this.timeSinceLastHeartbeat.getDeltaTime()),this.isStarted&&(t.timeSinceStarted=this.timeSinceStarted.getDeltaTime()),this.isPaused&&(t.timeSincePaused=this.timeSincePaused.getDeltaTime()),this.isBuffering&&(t.timeSinceBufferBegin=this.timeSinceBufferBegin.getDeltaTime()),this.isSeeking&&(t.timeSinceSeekBegin=this.timeSinceSeekBegin.getDeltaTime()),t.timeSinceLastAd=this.timeSinceLastAd.getDeltaTime(),this.numberOfErrors>0&&this.timeSinceLastError.startTime>0&&(t.timeSinceLastError=this.timeSinceLastError.getDeltaTime()),t.numberOfVideos=this.numberOfVideos),t.numberOfErrors=this.numberOfErrors,this.isAd()||(this.playtimeSinceLastEvent.startTime>0?t.playtimeSinceLastEvent=this.playtimeSinceLastEvent.getDeltaTime():t.playtimeSinceLastEvent=0,this.isPlaying?this.playtimeSinceLastEvent.start():this.playtimeSinceLastEvent.reset(),this.totalPlaytime+=t.playtimeSinceLastEvent,t.totalPlaytime=this.totalPlaytime);for(const[e,i]of Object.entries(this.customTimeSinceAttributes))t[e]=i.getDeltaTime();return t}getQoeAttributes(t){t=t||{};const e={};try{if(null!==this.startupTime&&(e.startupTime=this.startupTime),this.peakBitrate>0&&(e.peakBitrate=this.peakBitrate),e.hadStartupError=this.hadStartupError,e.hadPlaybackError=this.hadPlaybackError,e.totalRebufferingTime=this.totalRebufferingTime,e.rebufferingRatio=this.totalPlaytime>0?this.totalRebufferingTime/this.totalPlaytime*100:0,e.totalPlaytime=this.totalPlaytime,e.averageBitrate=this.weightedBitrate,e.numberOfErrors=this.numberOfErrors,this._downloadBitrates.length>0){const t=this._downloadBitrates.reduce((t,e)=>t+e,0);e.avgDownloadRate=Math.round(t/this._downloadBitrates.length),e.minDownloadRate=Math.min(...this._downloadBitrates),e.maxDownloadRate=Math.max(...this._downloadBitrates)}e.totalSwitchUps=this.totalSwitchUps,e.totalSwitchDowns=this.totalSwitchDowns,e.totalPauseTime=this.timeSincePaused.getDuration(),e.totalViewSessionTime=this.totalPlaytime,e.totalRenditions=this._playedRenditions.size,e.qoeAggregateVersion="1.1.0"}catch(t){n.error("Failed to add attributes for QOE KPIs",t.message)}return t.qoe=e,t}calculateBufferType(t){let e="";return e=t?"initial":this.isSeeking?"seek":this.isPaused?"pause":"connection",n.debug("Buffer Type = "+e),e}goViewCountUp(){this._viewCount++}goPlayerReady(){return!this.isPlayerReady&&(this.isPlayerReady=!0,!0)}goRequest(){return!this.isRequested&&(this.isRequested=!0,this.timeSinceLastAd.reset(),this.timeSinceRequested.start(),!0)}goStart(){return!(!this.isRequested||this.isStarted)&&(this.isAd()?this.numberOfAds++:this.numberOfVideos++,this.isStarted=!0,this.isPlaying=!0,this.timeSinceStarted.start(),this.playtimeSinceLastEvent.start(),!0)}goEnd(){return!!this.isRequested&&(this.numberOfErrors=0,this.resetFlags(),this.timeSinceRequested.stop(),this.timeSinceStarted.stop(),this.playtimeSinceLastEvent.stop(),this.isPlaying=!1,!0)}goPause(){return!(!this.isStarted||this.isPaused)&&(this.isPaused=!0,this.isPlaying=!1,this.timeSincePaused.start(),this.playtimeSinceLastEvent.stop(),this.timeSinceResumed.reset(),this.isBuffering&&(this._bufferAcc+=this.bufferElapsedTime.getDeltaTime()),this.elapsedTime.start(),!0)}goResume(){return!(!this.isStarted||!this.isPaused)&&(this.isPaused=!1,this.isPlaying=!0,this.timeSincePaused.stop(),this.timeSinceResumed.start(),this._hb?(this._acc=this.elapsedTime.getDeltaTime(),this._hb=!1):(this.isBuffering&&this.bufferElapsedTime.start(),this._acc+=this.elapsedTime.getDeltaTime()),!0)}goBufferStart(){return!(!this.isRequested||this.isBuffering)&&(this.isBuffering=!0,this.isPlaying=!1,this.timeSinceBufferBegin.start(),this.bufferElapsedTime.start(),!0)}goBufferEnd(){return!(!this.isRequested||!this.isBuffering)&&(this.isBuffering=!1,this.isPlaying=!0,this.timeSinceBufferBegin.stop(),this._hb?(this._bufferAcc=this.bufferElapsedTime.getDeltaTime(),this._hb=!1):this._bufferAcc+=this.bufferElapsedTime.getDeltaTime(),!this.isAd()&&this.initialBufferingHappened&&(this.totalRebufferingTime+=this.timeSinceBufferBegin.stopTime-this.timeSinceBufferBegin.startTime),!0)}goSeekStart(){return!(!this.isStarted||this.isSeeking)&&(this.isSeeking=!0,this.isPlaying=!1,this.timeSinceSeekBegin.start(),this.timeSinceSeekEnd.reset(),!0)}goSeekEnd(){return!(!this.isStarted||!this.isSeeking)&&(this.isSeeking=!1,this.isPlaying=!0,this.timeSinceSeekBegin.stop(),this.timeSinceSeekEnd.start(),!0)}goAdBreakStart(){return!this.isAdBreak&&(this.isAdBreak=!0,this.timeSinceAdBreakStart.start(),!0)}goAdBreakEnd(){return!!this.isAdBreak&&(this.isRequested=!1,this.isAdBreak=!1,this.totalAdPlaytime=this.timeSinceAdBreakStart.getDeltaTime(),this.timeSinceAdBreakStart.stop(),!0)}goDownload(){this.timeSinceLastDownload.start()}goHeartbeat(){this.timeSinceLastHeartbeat.start()}goRenditionChange(){this.timeSinceLastRenditionChange.start()}goAdQuartile(){this.timeSinceLastAdQuartile.start()}goError(){this.isError=!0,this.numberOfErrors++,this.isAd()?this.timeSinceLastAdError.start():(this.timeSinceLastError.start(),this.isStarted?this.hadPlaybackError=!0:this.hadStartupError=!0)}goLastAd(){this.timeSinceLastAd.start()}trackContentBitrateState(t){if(t&&"number"==typeof t){this.peakBitrate=Math.max(this.peakBitrate,t);const e=Date.now();if(!this.isPlaying){if(null!==this._lastBitrate&&null!==this._lastBitrateChangeTimestamp){const t=e-this._lastBitrateChangeTimestamp;t>0&&(this.partialAverageBitrate+=this._lastBitrate*t,this._totalBitrateDuration+=t),this._lastBitrateChangeTimestamp=null}return void(this._lastBitrate=t)}if(null===this._lastBitrateChangeTimestamp&&null!==this._lastBitrate&&(this._lastBitrateChangeTimestamp=e),null!==this._lastBitrate&&this._lastBitrate!==t&&null!==this._lastBitrateChangeTimestamp){const t=e-this._lastBitrateChangeTimestamp;t>0&&(this.partialAverageBitrate+=this._lastBitrate*t,this._totalBitrateDuration+=t),this._lastBitrateChangeTimestamp=e}null===this._lastBitrateChangeTimestamp&&(this._lastBitrateChangeTimestamp=e),this._lastBitrate=t;let i=this.partialAverageBitrate,s=this._totalBitrateDuration;const r=e-this._lastBitrateChangeTimestamp;r>0&&(i+=t*r,s+=r),this.weightedBitrate=s>0?Math.round(i/s):t}}trackDownloadRate(t){!t||"number"!=typeof t||t<=0||t!==this._lastDownloadBitrate&&(this._downloadBitrates.push(t),this._lastDownloadBitrate=t)}addPlayedRendition(t,e){t&&e&&this._playedRenditions.add(`${t}x${e}`)}resetViewIdTrackedState(){this.peakBitrate=0,this.startupTime=null,this.partialAverageBitrate=0,this._totalBitrateDuration=0,this.weightedBitrate=0,this._lastBitrate=null,this._lastBitrateChangeTimestamp=null,this._downloadBitrates=[],this._lastDownloadBitrate=null,this.totalSwitchUps=0,this.totalSwitchDowns=0,this.timeSincePaused.reset(),this._playedRenditions=new Set}clearTotalAdsTime(){n.debug("clear total ads time",this.totalAdTime),this._totalAdPlaytime.reset()}totalAdTime(){return this._totalAdPlaytime.getDuration()}startAdsTime(){return n.debug("startAdsTime"),this._totalAdPlaytime.start()}stopAdsTime(){return n.debug("stopAdsTime"),this._totalAdPlaytime.stop()}setStartupTime(t){null===this.startupTime&&(this.startupTime=Math.max(this.timeSinceRequested.getDeltaTime()-t,0))}};class k extends m{constructor(t,e){super(),this.state=new D,this.adsTracker=null,this._lastBufferType=null,this._userId=null,this._src=null,e=e||{},this.setOptions(e),t&&this.setPlayer(t,e.tag),n.notice("Tracker "+this.getTrackerName()+" v"+this.getTrackerVersion()+" is ready.")}setUserId(t){this._userId=t}setOptions(t){t&&(t.adsTracker&&this.setAdsTracker(t.adsTracker),"boolean"==typeof t.isAd&&this.setIsAd(t.isAd),void 0!==t.src&&(null!==this._src&&this._src!==t.src?n.warn(`setOptions: src is locked to '${this._src}'. Ignoring override '${t.src}'.`):(this._src=t.src,this.adsTracker&&null==this.adsTracker._src&&(this.adsTracker._src=this._src))),m.prototype.setOptions.apply(this,arguments))}setPlayer(t,e){(this.player||this.tag)&&this.dispose(),"undefined"!=typeof document&&document.getElementById&&("string"==typeof t&&(t=document.getElementById(t)),"string"==typeof e&&(e=document.getElementById(e))),e=e||t,this.player=t,this.tag=e,this.registerListeners()}isAd(){return this.state.isAd()}setIsAd(t){this.state.setIsAd(t)}setAdsTracker(t){this.disposeAdsTracker(),t&&(this.adsTracker=t,this.adsTracker.setIsAd(!0),this.adsTracker.parentTracker=this,null!=this._src&&null==t._src&&(t._src=this._src),this.adsTracker.on("*",N.bind(this)))}disposeAdsTracker(){this.adsTracker&&(this.adsTracker.off("*",N),this.adsTracker.dispose())}dispose(){this.stopHeartbeat(),this.disposeAdsTracker(),this.unregisterListeners(),this.player=null,this.tag=null}registerListeners(){}unregisterListeners(){}getViewId(){return this.parentTracker?this.parentTracker.getViewId():this.state.getViewId()}getViewSession(){return this.parentTracker?this.parentTracker.getViewSession():this.state.getViewSession()}getVideoId(){return null}getTitle(){return null}isLive(){return null}getBitrate(){return null}getManifestBitrate(){return null}getSegmentDownloadBitrate(){return null}getNetworkDownloadBitrate(){return null}getWebkitBitrate(){if(this.tag&&this.tag.webkitVideoDecodedByteCount){let t;if(this._lastWebkitBitrate){t=this.tag.webkitVideoDecodedByteCount;let e=t-this._lastWebkitBitrate,i=this.getHeartbeat()/1e3;t=Math.round(e/i*8)}return this._lastWebkitBitrate=this.tag.webkitVideoDecodedByteCount,t||null}}getRenditionName(){return null}getRenditionBitrate(){return null}getRenditionShift(t){let e,i=this.getManifestBitrate();return this.isAd()?(e=this._lastAdRendition,t&&(this._lastAdRendition=i)):(e=this._lastRendition,t&&(this._lastRendition=i)),i&&e?i>e?"up":i<e?"down":null:null}getRenditionHeight(){return this.tag?this.tag.videoHeight:null}getRenditionWidth(){return this.tag?this.tag.videoWidth:null}getDuration(){return this.tag?this.tag.duration:null}getPlayhead(){return this.tag?this.tag.currentTime:null}getLanguage(){return null}getSrc(){return this.tag?this.tag.currentSrc:null}getPlayrate(){return this.tag?this.tag.playbackRate:null}isMuted(){return this.tag?this.tag.muted:null}isFullscreen(){return null}getCdn(){return null}getPlayerName(){return this.getTrackerName()}getPlayerVersion(){return d.rE}getFps(){return null}isAutoplayed(){return this.tag?this.tag.autoplay:null}getPreload(){return this.tag?this.tag.preload:null}getAdQuartile(){return null}getAdPosition(){return this.parentTracker?this.parentTracker.state.isStarted?"mid":"pre":null}getAdPartner(){return null}getAdCreativeId(){return null}getInstrumentationProvider(){return null}getInstrumentationName(){return null}getInstrumentationVersion(){return null}getAttributes(t,e){if(void 0===(t=m.prototype.getAttributes.apply(this,arguments)).isAd&&(t.isAd=this.isAd()),t.viewSession=this.getViewSession(),t.viewId=this.getViewId(),t.playerName=this.getPlayerName(),t.playerVersion=this.getPlayerVersion(),t["instrumentation.provider"]=this.getInstrumentationProvider(),t["instrumentation.name"]=this.getInstrumentationName(),t["instrumentation.version"]=this.getInstrumentationVersion(),t["enduser.id"]=this._userId,t.src=this._src||"Browser","customAction"===e)return t;try{t.pageUrl=window.location.href}catch(t){}this.isAd()?(t.adId=this.getVideoId(),t.adTitle=this.getTitle(),t.adSrc=this.getSrc(),t.adCdn=this.getCdn(),this.state.isStarted&&(t.adBitrate=this.getBitrate()||0),t.adRenditionName=this.getRenditionName(),t.adRenditionHeight=this.getRenditionHeight(),t.adRenditionWidth=this.getRenditionWidth(),t.adDuration=this.getDuration(),t.adPlayhead=this.getPlayhead(),t.adLanguage=this.getLanguage(),t.adIsMuted=this.isMuted(),t.adFps=this.getFps(),t.adPosition=this.getAdPosition(),t.adCreativeId=this.getAdCreativeId(),t.adPartner=this.getAdPartner()):(t.contentId=this.getVideoId(),t.contentTitle=this.getTitle(),t.contentSrc=this.getSrc(),t.contentCdn=this.getCdn(),t.contentPlayhead=this.getPlayhead(),t.contentIsLive=this.isLive(),this.state.isStarted&&(t.contentBitrate=this.getBitrate()||0,t.contentManifestBitrate=this.getManifestBitrate()||0,t.contentSegmentDownloadBitrate=this.getSegmentDownloadBitrate()||0,t.contentNetworkDownloadBitrate=this.getNetworkDownloadBitrate()||0),t.contentRenditionName=this.getRenditionName(),t.contentRenditionHeight=this.getRenditionHeight(),t.contentRenditionWidth=this.getRenditionWidth(),t.contentDuration=this.getDuration(),t.contentLanguage=this.getLanguage(),t.contentPlayrate=this.getPlayrate(),t.contentIsFullscreen=this.isFullscreen(),t.contentIsMuted=this.isMuted(),t.contentIsAutoplayed=this.isAutoplayed(),t.contentPreload=this.getPreload(),t.contentFps=this.getFps(),null!=this.adsTracker&&this.adsTracker.state.totalAdPlaytime>0&&(t.totalAdPlaytime=this.adsTracker.state.totalAdPlaytime)),this.state.getStateAttributes(t),this.state.isStarted&&!this.isAd()&&(this.state.trackContentBitrateState(t.contentBitrate),this.state.trackDownloadRate(t.contentNetworkDownloadBitrate),this.state.addPlayedRendition(t.contentRenditionHeight,t.contentRenditionWidth));for(let e in this.customData)t[e]=this.customData[e];if(!this.isAd()){this.state.getQoeAttributes(t);const e=t.qoe;for(let t in this.customData)e[t]=this.customData[t]}return t}sendCustom(t,e,i){i=i||{},this.sendVideoCustomAction(t,i),this.state.setTimeSinceAttribute(e)}sendPlayerReady(t){this.state.goPlayerReady()&&(t=t||{},this.sendVideoAction(k.Events.PLAYER_READY,t))}sendRequest(t){if(this.state.goRequest()){let e;this.isAd()?(e=k.Events.AD_REQUEST,this.sendVideoAdAction(e,t)):(e=k.Events.CONTENT_REQUEST,this.sendVideoAction(e,t))}}sendStart(t){if(this.state.goStart()){let e;if(this.isAd())e=k.Events.AD_START,this.parentTracker&&(this.parentTracker.state.isPlaying=!1),this.sendVideoAdAction(e,t),this.state.startAdsTime();else{e=k.Events.CONTENT_START;let i=0;this.adsTracker&&((this.adsTracker.state.isPlaying||this.adsTracker.state.isBuffering)&&(this.adsTracker.state.stopAdsTime(),this.adsTracker.state.isPlaying=!1,this.adsTracker.state.isBuffering=!1),i=this.adsTracker.state.totalAdTime()??0),this.state.setStartupTime(i),this.sendVideoAction(e,t);const s=this.getHarvester?.();s?.setBeforeDrainCallback(()=>{if(this.state){const t=this.state.getQoeAttributes({}).qoe;s.refreshQoeKpis(t,this.getViewId())}})}this.startHeartbeat(),this.state.goHeartbeat()}}sendEnd(t){if(this.state.goEnd()){let e;if(t=t||{},this.isAd()?(e=k.Events.AD_END,t.timeSinceAdRequested=this.state.timeSinceRequested.getDeltaTime(),t.timeSinceAdStarted=this.state.timeSinceStarted.getDeltaTime(),this.parentTracker&&(this.parentTracker.state.isPlaying=!0,this.parentTracker.state.timeSincePaused.reset()),this.state.stopAdsTime()):(e=k.Events.CONTENT_END,t.timeSinceRequested=this.state.timeSinceRequested.getDeltaTime(),t.timeSinceStarted=this.state.timeSinceStarted.getDeltaTime()),this.stopHeartbeat(),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t),this.parentTracker&&this.isAd()&&this.parentTracker.state.goLastAd(),this.state.goViewCountUp(),this.state.totalPlaytime=0,!this.isAd()){const t=this.getHarvester?.();t?.forceNextQoeCycle?.(),t?.setBeforeDrainCallback?.(null),this.adsTracker&&this.adsTracker.state.clearTotalAdsTime(),this.state.resetViewIdTrackedState()}}}sendPause(t){if(this.state.goPause()){let e=this.isAd()?k.Events.AD_PAUSE:k.Events.CONTENT_PAUSE;this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendResume(t){if(this.state.goResume()){let e;t=t||{},this.isAd()?(e=k.Events.AD_RESUME,t.timeSinceAdPaused=this.state.timeSincePaused.getDeltaTime()):(e=k.Events.CONTENT_RESUME,t.timeSincePaused=this.state.timeSincePaused.getDeltaTime()),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendBufferStart(t){if(this.state.goBufferStart()){let e;t=t||{},e=this.isAd()?k.Events.AD_BUFFER_START:k.Events.CONTENT_BUFFER_START,t=this.buildBufferAttributes(t),this._lastBufferType=t.bufferType,this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendBufferEnd(t){if(this.state.goBufferEnd()){let e;t=t||{},this.isAd()?(e=k.Events.AD_BUFFER_END,t.timeSinceAdBufferBegin=this.state.timeSinceBufferBegin.getDeltaTime()):(e=k.Events.CONTENT_BUFFER_END,t.timeSinceBufferBegin=this.state.timeSinceBufferBegin.getDeltaTime()),t=this.buildBufferAttributes(t),null!=this._lastBufferType&&(t.bufferType=this._lastBufferType),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t),this.state.initialBufferingHappened=!0}}buildBufferAttributes(t){return null==t.timeSinceStarted||t.timeSinceStarted<100?t.isInitialBuffering=!this.state.initialBufferingHappened:t.isInitialBuffering=!1,t.bufferType=this.state.calculateBufferType(t.isInitialBuffering),t.timeSinceResumed=this.state.timeSinceResumed.getDeltaTime(),t.timeSinceSeekEnd=this.state.timeSinceSeekEnd.getDeltaTime(),t}sendSeekStart(t){if(this.state.goSeekStart()){let e;e=this.isAd()?k.Events.AD_SEEK_START:k.Events.CONTENT_SEEK_START,this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendSeekEnd(t){if(this.state.goSeekEnd()){let e;t=t||{},this.isAd()?(e=k.Events.AD_SEEK_END,t.timeSinceAdSeekBegin=this.state.timeSinceSeekBegin.getDeltaTime()):(e=k.Events.CONTENT_SEEK_END,t.timeSinceSeekBegin=this.state.timeSinceSeekBegin.getDeltaTime()),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendDownload(t){(t=t||{}).state||n.warn("Called sendDownload without { state: xxxxx }."),this.sendVideoAction(k.Events.DOWNLOAD,t),this.state.goDownload()}sendError(t){(t=t||{}).isAd=this.isAd(),this.state.goError();let e=this.isAd()?k.Events.AD_ERROR:k.Events.CONTENT_ERROR;this.sendVideoErrorAction(e,t)}sendRenditionChanged(t){(t=t||{}).timeSinceLastRenditionChange=this.state.timeSinceLastRenditionChange.getDeltaTime();const{oldBitrate:e,newBitrate:i}=t;let s;this.isAd()||void 0===e||void 0===i||(i>e?(t.shift="up",this.state.totalSwitchUps+=1):i<e?(t.shift="down",this.state.totalSwitchDowns+=1):t.shift=null),delete t.oldBitrate,delete t.newBitrate,s=this.isAd()?k.Events.AD_RENDITION_CHANGE:k.Events.CONTENT_RENDITION_CHANGE,this.isAd()?this.sendVideoAdAction(s,t):this.sendVideoAction(s,t),this.state.goRenditionChange()}sendHeartbeat(t){if(this.state.isRequested){let e,i=this.getHeartbeat();this.state._hb=!0,i=this.adjustElapsedTimeForPause(i),this.isAd()?(e=k.Events.AD_HEARTBEAT,"bitmovin-ads"===this.getPlayerName()?this.sendVideoAdAction(e,t):this.sendVideoAdAction(e,{elapsedTime:i,...t})):(e=k.Events.CONTENT_HEARTBEAT,this.sendVideoAction(e,{elapsedTime:i,...t})),this.state.goHeartbeat()}}adjustElapsedTimeForPause(t){return this.state._acc&&(t-=this.state._acc,this.state._acc=0),this.state.isPaused&&((t-=this.state.elapsedTime.getDeltaTime())<10&&(t=0),this.state.elapsedTime.start()),this.state._bufferAcc?(t-=this.state._bufferAcc,this.state._bufferAcc=0):this.state.isBuffering&&((t-=this.state.bufferElapsedTime.getDeltaTime())<5&&(t=0),this.state.bufferElapsedTime.start()),Math.max(0,t)}sendAdBreakStart(t){this.isAd()&&this.state.goAdBreakStart()&&(this.state.totalAdPlaytime=0,this.parentTracker&&(this.parentTracker.state.isPlaying=!1),this.sendVideoAdAction(k.Events.AD_BREAK_START,t))}sendAdBreakEnd(t){this.isAd()&&this.state.goAdBreakEnd()&&((t=t||{}).timeSinceAdBreakBegin=this.state.timeSinceAdBreakStart.getDeltaTime(),this.sendVideoAdAction(k.Events.AD_BREAK_END,t),this.parentTracker&&(this.parentTracker.state.isPlaying=!0),this.stopHeartbeat(),this.parentTracker&&this.isAd()&&this.parentTracker.state.goLastAd())}sendAdQuartile(t){this.isAd()&&((t=t||{}).quartile||n.warn("Called sendAdQuartile without { quartile: xxxxx }."),t.timeSinceLastAdQuartile=this.state.timeSinceLastAdQuartile.getDeltaTime(),this.sendVideoAdAction(k.Events.AD_QUARTILE,t),this.state.goAdQuartile())}sendAdClick(t){this.isAd()&&((t=t||{}).url||n.warn("Called sendAdClick without { url: xxxxx }."),this.sendVideoAdAction(k.Events.AD_CLICK,t))}}function N(t){t.type!==k.Events.AD_ERROR?this.sendVideoAdAction(t.type,t.data):this.sendVideoErrorAction(t.type,t.data)}k.Events={PLAYER_READY:"PLAYER_READY",DOWNLOAD:"DOWNLOAD",ERROR:"ERROR",CONTENT_REQUEST:"CONTENT_REQUEST",CONTENT_START:"CONTENT_START",CONTENT_END:"CONTENT_END",CONTENT_PAUSE:"CONTENT_PAUSE",CONTENT_RESUME:"CONTENT_RESUME",CONTENT_SEEK_START:"CONTENT_SEEK_START",CONTENT_SEEK_END:"CONTENT_SEEK_END",CONTENT_BUFFER_START:"CONTENT_BUFFER_START",CONTENT_BUFFER_END:"CONTENT_BUFFER_END",CONTENT_HEARTBEAT:"CONTENT_HEARTBEAT",CONTENT_RENDITION_CHANGE:"CONTENT_RENDITION_CHANGE",CONTENT_ERROR:"CONTENT_ERROR",AD_REQUEST:"AD_REQUEST",AD_START:"AD_START",AD_END:"AD_END",AD_PAUSE:"AD_PAUSE",AD_RESUME:"AD_RESUME",AD_SEEK_START:"AD_SEEK_START",AD_SEEK_END:"AD_SEEK_END",AD_BUFFER_START:"AD_BUFFER_START",AD_BUFFER_END:"AD_BUFFER_END",AD_HEARTBEAT:"AD_HEARTBEAT",AD_RENDITION_CHANGE:"AD_RENDITION_CHANGE",AD_ERROR:"AD_ERROR",AD_BREAK_START:"AD_BREAK_START",AD_BREAK_END:"AD_BREAK_END",AD_QUARTILE:"AD_QUARTILE",AD_CLICK:"AD_CLICK"};const C=k,{MAX_PAYLOAD_SIZE:O,MAX_EVENTS_PER_BATCH:I}=h;class P{constructor(){this.buffer=[],this.maxPayloadSize=O,this.maxEventsPerBatch=I,this.currentPayloadSize=0,this.totalEvents=0,this.smartHarvestPayloadThreshold=Math.floor(.6*this.maxPayloadSize),this.overflowPayloadThreshold=Math.floor(.9*this.maxPayloadSize),this.smartHarvestEventThreshold=Math.floor(.6*this.maxEventsPerBatch),this.overflowEventThreshold=Math.floor(.9*this.maxEventsPerBatch),this.onSmartHarvestTrigger=null}addOrReplaceByActionName(t,e){const i=this.buffer.findIndex(e=>e.actionName===t);try{return-1===i?this.add(e):this.add(e,i),!0}catch(t){return n.error("Failed to set or replace the event to buffer:",t.message),!1}}addOrReplaceByActionNameAndViewId(t,e,i){const s=this.buffer.findIndex(i=>i.actionName===t&&i.viewId===e);try{return-1===s?this.add(i):this.add(i,s),!0}catch(t){return n.error("Failed to set or replace the event to buffer:",t.message),!1}}findByActionNameAndViewId(t,e){return this.buffer.find(i=>i.actionName===t&&i.viewId===e)||null}findByActionName(t){return this.buffer.find(e=>e.actionName===t)||null}add(t,e){try{const i=E(t),s=this.currentPayloadSize+i>=this.maxPayloadSize,r=this.totalEvents+1>=this.maxEventsPerBatch;if((s||r)&&this.makeRoom(i),null!=e&&e>-1){const s=E(this.buffer[e]);this.buffer[e]=t,this.currentPayloadSize+=i-s}else this.buffer.push(t),this.totalEvents++,this.currentPayloadSize+=i;return this.checkSmartHarvestTrigger(),!0}catch(t){return n.error("Failed to add event to buffer:",t.message),!1}}checkSmartHarvestTrigger(){const t=this.currentPayloadSize/this.maxPayloadSize,e=this.totalEvents/this.maxEventsPerBatch,i=this.currentPayloadSize>=this.overflowPayloadThreshold,s=this.totalEvents>=this.overflowEventThreshold;if(i||s){const s=i?`payload ${this.currentPayloadSize}/${this.maxPayloadSize} bytes (${Math.round(100*t)}%)`:`events ${this.totalEvents}/${this.maxEventsPerBatch} (${Math.round(100*e)}%)`;n.warn(`OVERFLOW PREVENTION: ${s} - Emergency harvest triggered`),this.onSmartHarvestTrigger&&"function"==typeof this.onSmartHarvestTrigger&&this.onSmartHarvestTrigger("overflow",90)}else{const t=this.currentPayloadSize>=this.smartHarvestPayloadThreshold,e=this.totalEvents>=this.smartHarvestEventThreshold;(t||e)&&this.onSmartHarvestTrigger&&"function"==typeof this.onSmartHarvestTrigger&&this.onSmartHarvestTrigger("smart",60)}}setSmartHarvestCallback(t){this.onSmartHarvestTrigger=t}drain(){try{const t=this.buffer.splice(0);return this.totalEvents=0,this.currentPayloadSize=0,t}catch(t){return n.error("Failed to drain events from buffer:",t.message),[]}}isEmpty(){return 0===this.totalEvents}size(){return this.totalEvents}clear(){this.buffer=[],this.totalEvents=0}makeRoom(t){if(t>this.maxPayloadSize)n.error("Event dropped: Event size exceeds maximum payload size.");else for(;(this.totalEvents>=this.maxEventsPerBatch||this.currentPayloadSize+t>=this.maxPayloadSize)&&this.buffer.length>0;){const t=E(this.buffer.shift());this.totalEvents--,this.currentPayloadSize-=t,n.warn("Event buffer full, oldest event removed.")}}}const{MAX_PAYLOAD_SIZE:V,MAX_EVENTS_PER_BATCH:L}=h;class H{constructor(){this.retryQueue=[],this.maxQueueSize=L,this.maxQueueSizeBytes=V}addFailedEvents(t){try{const e=Array.isArray(t)?t:[t];n.notice(`Adding ${e.length} failed events to retry queue`,{queueSizeBefore:this.retryQueue.length});for(const t of e){this.retryQueue.length>=this.maxQueueSize&&this.evictOldestEvent();const e=E(t);for(;E(this.retryQueue)+e>this.maxQueueSizeBytes;)this.evictOldestEvent();this.retryQueue.push({...t})}}catch(t){n.error("Failed to add events to retry queue:",t.message)}}discardEvent(t,e){n.warn("Discarded event",{reason:e,eventType:t.eventType})}evictOldestEvent(){if(this.retryQueue.length>0){const t=this.retryQueue.shift();this.discardEvent(t,"Queue full - evicted oldest")}}getRetryEventsToFit(t,e){const i=[];let s=0,r=0;for(let a=this.retryQueue.length-1;a>=0;a--){const n=this.retryQueue[a];if(r>=e)break;const o=E(n);if(s+o>t)break;i.unshift(n),s+=o,r++,this.retryQueue.splice(a,1)}return i}getQueueSize(){return this.retryQueue.length}clear(){this.retryQueue=[]}}class F{async send(t,e){const{url:i,payload:s,options:r={}}=t;try{if(!i||!s)throw new Error("URL and payload are required");const t={url:i,payload:s,options:r,callback:e};await this.executeRequest(t)}catch(t){n.error("Failed to send request:",t.message),e({retry:!1,status:0,error:t.message})}}async executeRequest(t){const{url:e,payload:i,options:s,callback:r}=t,a=Date.now();try{const r=(o=JSON.stringify(i.body),h=window.NRVIDEO?.config?.obfuscate,h&&0!==h.length?h.reduce((t,e)=>{let i;try{if(e.regex instanceof RegExp){const t=e.regex.flags.includes("g")?e.regex.flags:e.regex.flags+"g";i=new RegExp(e.regex.source,t)}else i=new RegExp(e.regex,"g")}catch(i){return n.warn("applyObfuscationRules: invalid regex, skipping rule:",e.regex,i.message),t}return t.replace(i,e.replacement)},o):o);if(s.isFinalHarvest&&navigator.sendBeacon){const i=await this.sendWithBeacon(e,r),s={success:i,status:i?204:0};return void this.handleRequestComplete(t,s,a)}const d=await this.fetchWithTimeout(e,{method:"POST",body:r,headers:{"Content-Type":"application/json"},keepalive:s.isFinalHarvest},1e4),l={success:d.ok,status:d.status,statusText:d.statusText};this.handleRequestComplete(t,l,a)}catch(e){const i={success:!1,status:0,error:e.message};this.handleRequestComplete(t,i,a)}var o,h}handleRequestComplete(t,e){const{callback:i}=t;i({retry:!e.success&&(0===e.status||function(t){switch(t){case 408:case 429:case 500:return!0;case 401:case 403:case 404:return!1}return t>=502&&t<=504||t>=512&&t<=530}(e.status)),status:e.status,error:e.error})}async sendWithBeacon(t,e){try{return navigator.sendBeacon(t,e)}catch(t){return n.warn("sendBeacon failed, falling back to fetch:",t.message),!1}}async fetchWithTimeout(t,e,i){const s=new AbortController,r=setTimeout(()=>s.abort(),i);try{const i=await fetch(t,{...e,signal:s.signal});return clearTimeout(r),i}catch(t){if(clearTimeout(r),"AbortError"===t.name)throw new Error(`Request timeout after ${i}ms`);throw t}}}function Q(t,e){const i=t[e.viewId];if(!i)return!1;for(const t of h.QOE_KPI_KEYS)if(e[t]!==i[t])return!1;return!0}function x(t,e){const i={};for(const t of h.QOE_KPI_KEYS)i[t]=e[t];t[e.viewId]=i}class q{constructor(t){this.eventBuffer=t,this.retryQueueHandler=new H,this.httpClient=new F,this.fallBackUrl="",this.retryCount=0,this.eventBuffer instanceof P&&this.eventBuffer.setSmartHarvestCallback((t,e)=>this.triggerSmartHarvest(t,e)),this.harvestCycle=h.INTERVAL,this.isHarvesting=!1,this.qoeCycleCount=1,this.forceNextQoeCycle=!1,this.beforeDrainCallback=null,this._lastSentQoeKpis={},this.timer=function({interval:t,onTick:e,errorLabel:i}){let s=!1,r=null,a=t;function o(){s&&(r=setTimeout(async()=>{r=null;try{await e()}catch(t){n.error(`${i}: scheduled tick failed:`,t.message)}finally{s&&o()}},a))}return{start(){s||(s=!0,o())},stop(){s=!1,r&&(clearTimeout(r),r=null)},cancelAndReschedule(){r&&(clearTimeout(r),r=null),s&&o()},updateInterval(t){"number"!=typeof t||t<=0||(a=t,s&&r&&(clearTimeout(r),r=null,o()))},isRunning:()=>s}}({interval:this.harvestCycle,onTick:()=>this.onHarvestInterval(),errorLabel:"HarvestScheduler"}),this.setupPageLifecycleHandlers()}get isStarted(){return this.timer.isRunning()}startScheduler(){this.timer.isRunning()?n.warn("Harvest scheduler is already started"):(n.notice("Starting harvest scheduler",{harvestCycle:this.harvestCycle,eventBufferSize:this.eventBuffer?this.eventBuffer.size():0}),this.timer.start())}stopScheduler(){this.timer.isRunning()&&(this.timer.stop(),n.notice("Harvest scheduler stopped"))}async triggerSmartHarvest(t,e){if(n.notice(`${t} harvest triggered at ${e}% threshold`,{type:t,threshold:e}),this.eventBuffer&&!this.eventBuffer.isEmpty())try{await this.triggerHarvest({})}catch(e){n.error(`${t} harvest failed:`,e.message)}finally{this.timer.cancelAndReschedule()}}async onHarvestInterval(){const t=this.eventBuffer&&!this.eventBuffer.isEmpty(),e=this.retryQueueHandler&&this.retryQueueHandler.getQueueSize()>0;(t||e)&&await this.triggerHarvest({})}async triggerHarvest(t={}){if(this.isHarvesting)return{success:!1,reason:"harvest_in_progress"};this.isHarvesting=!0;try{let e=this.drainEvents(t);if(t.isFinalHarvest){const t=h.MAX_BEACON_SIZE;E(e)>t&&(e=this.trimEventsToFit(e,t))}const i=await this.sendChunk(e,t,!0);return{success:i.success,totalChunks:1,results:[i]}}catch(t){return n.error("Harvest cycle failed:",t.message),this.handleHarvestFailure(t),{success:!1,error:t.message}}finally{this.isHarvesting=!1}}trimEventsToFit(t,e){if(0===t.length)return t;const i=[];let s=0;for(let r=t.length-1;r>=0;r--){const a=t[r],n=E({ins:[a,...i]});n>e||(i.unshift(a),s=n)}const r=t.length-i.length;if(r>0){const a=t.slice(0,r);n.warn(`Discarded ${r} events to fit beacon size limit`,{originalCount:t.length,trimmedCount:i.length,finalSize:s,maxSize:e}),this.retryQueueHandler&&this.retryQueueHandler.addFailedEvents(a)}return i}drainEvents(t={}){const e=window.NRVIDEO?.config?.qoeIntervalFactor??1,i=!!t.isFinalHarvest||this.forceNextQoeCycle,s=(this.qoeCycleCount-1)%e==0||i;if(this.forceNextQoeCycle&&(this.forceNextQoeCycle=!1),this.beforeDrainCallback&&"function"==typeof this.beforeDrainCallback)try{this.beforeDrainCallback()}catch(t){n.error("Before drain callback failed:",t.message)}let r=function(t,e,i){if(e)return t;const s=[];for(const e of t)e.actionName===m.Events.QOE_AGGREGATE?i.add(e):s.push(e);return s}(this.eventBuffer.drain(),s,this.eventBuffer);this.qoeCycleCount++,function(t,e,i){for(let s=t.length-1;s>=0;s--){const r=t[s];r.actionName===m.Events.QOE_AGGREGATE&&(!i&&Q(e,r)?t.splice(s,1):x(e,r))}}(r,this._lastSentQoeKpis,i);let a=[...r],o=E(r);if(this.retryQueueHandler&&this.retryQueueHandler.getQueueSize()>0){const t=h.MAX_PAYLOAD_SIZE-o,e=h.MAX_EVENTS_PER_BATCH-a.length;if(t>0&&e>0){const i=this.retryQueueHandler.getRetryEventsToFit(t,e);i.length>0&&(a=[...i,...a])}}return a}async sendChunk(t,e,i){const s={url:function(t){try{if(!window.NRVIDEO||!window.NRVIDEO.info)throw new Error("NRVIDEO info is not available.");let{beacon:e,licenseKey:i,applicationID:s}=window.NRVIDEO.info;if(!e||!i)throw new Error("Options object provided by New Relic is not correctly initialized");return s?`https://${t||e}/ins/1/${i}?a=${s}&v=${d.rE}&ref=${window.location.href}&ca=VA`:`https://${t||e}/ins/1/${i}?&v=${d.rE}&ref=${window.location.href}&ca=VA`}catch(t){return console.error(t.message),null}}(this.fallBackUrl),payload:{body:{ins:t}},options:{...e,isLastChunk:i}};return new Promise(e=>{this.httpClient.send(s,i=>{i.retry?this.handleRequestFailure(t):(this.retryCount=0,this.fallBackUrl=""),e({success:!i.retry,status:i.status,error:i.error,chunk:t,eventCount:t.length})})})}handleRequestFailure(t){this.retryQueueHandler.addFailedEvents(t),"US"===window.NRVIDEO?.info?.region&&(this.retryCount++,this.retryCount>5?(this.retryCount=0,this.fallBackUrl=""):this.retryCount>=2&&(this.fallBackUrl=h.COLLECTOR.US[1]))}handleHarvestFailure(t){n.warn("Harvest failure handled",{error:t.message})}updateHarvestInterval(t){"number"!=typeof t||isNaN(t)?n.warn("Invalid newInterval provided to updateHarvestInterval"):t<1e3||t>3e5?n.warn("newInterval out of bounds (1000-300000), ignoring"):this.harvestCycle!==t&&(this.harvestCycle=t,n.notice("Updated harvestCycle:",this.harvestCycle),this.timer.updateInterval(t))}setupPageLifecycleHandlers(){let t=!1;const e=()=>{t||(t=!0,this.triggerHarvest({isFinalHarvest:!0,force:!0}))};document.addEventListener("visibilitychange",()=>{document.hidden&&e()}),window.addEventListener("pagehide",()=>{e()}),window.addEventListener("beforeunload",()=>{e()})}}const U=new class{constructor(){this.isInitialized=!1,this.harvestScheduler=null,this.eventBuffer=null}initialize(){if(this.isInitialized)n.warn("Video analytics agent already initialized");else try{this.eventBuffer=new P,this.harvestScheduler=new q(this.eventBuffer),this.harvestScheduler.startScheduler(),this.isInitialized=!0,n.notice("Video analytics agent initialized successfully")}catch(t){n.error("Failed to initialize video analytics agent:",t.message)}}addEvent(t){this.isInitialized||(n.warn("Video analytics agent not initialized, initializing now"),this.initialize());try{return function(t,e){return!!e&&(e.actionName===m.Events.QOE_AGGREGATE?e.viewId?t.addOrReplaceByActionNameAndViewId(m.Events.QOE_AGGREGATE,e.viewId,e):t.addOrReplaceByActionName(m.Events.QOE_AGGREGATE,e):t.add(e))}(this.eventBuffer,t)}catch(t){return n.error("Failed to add event to harvesting system:",t.message),!1}}setHarvestInterval(t){this.isInitialized||this.initialize(),this.harvestScheduler.updateHarvestInterval(t)}forceNextQoeCycle(){this.harvestScheduler&&(this.harvestScheduler.forceNextQoeCycle=!0)}setBeforeDrainCallback(t){this.harvestScheduler&&(this.harvestScheduler.beforeDrainCallback=t)}refreshQoeKpis(t,e){!function(t,e,i){if(!t||!e)return;const s=i?t.findByActionNameAndViewId(m.Events.QOE_AGGREGATE,i):t.findByActionName(m.Events.QOE_AGGREGATE);if(!s)return;const r={...s};for(const t of h.QOE_KPI_KEYS)t in e&&(r[t]=e[t]);i?t.addOrReplaceByActionNameAndViewId(m.Events.QOE_AGGREGATE,i,r):t.addOrReplaceByActionName(m.Events.QOE_AGGREGATE,r)}(this.eventBuffer,t,e)}};var z;z=U,T["Browser"]=z;const G=U,M={Constants:h,Chrono:u,Log:n,Emitter:l,Tracker:m,VideoTracker:C,VideoTrackerState:D,Core:w,version:d.rE,NrVideoEventAggregator:P,RetryQueueHandler:H,OptimizedHttpClient:F,HarvestScheduler:q,recordEvent:v};module.exports=e})();
|
|
3
|
+
//# sourceMappingURL=index.js.map
|