Skip to content

Commit 90e00e8

Browse files
Update proper destroying of hls playback and event listeners
1 parent c7a3351 commit 90e00e8

22 files changed

Lines changed: 496 additions & 373 deletions

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.0.1]
6+
- Resolved proper cleanup of HLS streams upon the viewComplete event.
7+
- Enhanced stream handling logic: when a new player instance is initialized while another is in progress, the SDK now correctly destroys the previous player’s data monitoring and seamlessly switches to capture analytics for the incoming player.
8+
59
## [1.0.0]
610

711
### Added
812
- **Integration with HLS**:
913
- Enabled video performance tracking using FastPix Data SDK, supporting HLS streams with user engagement metrics, playback quality monitoring, and real-time streaming diagnostics.
10-
- Provides robust error management and reporting capabilities for seamless HLS video performance tracking.
14+
- Provides robust error management and reporting capabilities for HLS video performance tracking.
1115
- Allows customizable behavior, including options to disable cookies, respect `Do Not Track` settings, and configure advanced error tracking and automatic error handling.
1216
- Includes support for custom metadata, enabling users to pass optional fields such as `video_id`, `video_title`, `video_duration`, and more.
13-
- Introduced event tracking for `videoChange` and `programChange` to handle seamless metadata updates during playback transitions.
17+
- Introduced event tracking for `videoChange` to handle metadata updates during playback transitions.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fastpixMetrix.tracker(videoPlayerElement, {
7474
});
7575

7676
// To stop monitoring call when destroying the HLS player
77-
// hlsPlayerInstance.fp.destroy();
77+
// videoPlayerElement.fp.destroy();
7878
```
7979

8080
After successfully completing Step 3, you can track viewer metrics in the FastPix dashboard once playback ends. Steps 4, 5, and 6 are optional and can be utilized as needed to enhance your integration.
@@ -124,7 +124,7 @@ fastpixMetrix.tracker(videoPlayerElement, {
124124
});
125125

126126
// To stop monitoring call when destroying the HLS player
127-
// hlsPlayerInstance.fp.destroy();
127+
// videoPlayerElement.fp.destroy();
128128
```
129129

130130
### Note:

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fastpix/video-data-core",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"author": "FastPix, Inc",
55
"license": "MIT",
66
"description": "FastPix Video Data SDK for real-time monitoring of HTML5 video players.",

src/CommonMethods/index.ts

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,19 @@ import {
77
} from "../IdGenerationMethod/index";
88

99
// Return Host & Domain Name
10-
const getHostAndDomainName = (endpoint: string): (string | undefined)[] => {
11-
if (typeof endpoint !== "string" || endpoint === "") {
12-
return ["localhost"];
13-
}
14-
let trackDomain: string | undefined;
15-
const trackHost: string | undefined = (endpoint.match(
16-
/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/,
17-
) || [])[4];
18-
19-
if (trackHost) {
20-
trackDomain = (trackHost.match(/[^.]+\.[^.]+$/) || [])[0];
10+
const getHostAndDomainName = (endpoint: string): [string, string] => {
11+
if (!endpoint) {
12+
return ["localhost", "localhost"];
2113
}
14+
try {
15+
const url = new URL(endpoint);
16+
const host = url.hostname;
17+
const parts = host.split(".");
18+
const domain = parts.length >= 2 ? parts.slice(-2).join(".") : host;
19+
return [host, domain];
20+
} catch {}
2221

23-
return [trackHost, trackDomain];
22+
return ["localhost", "localhost"];
2423
};
2524

2625
// Return Hostname
@@ -37,7 +36,7 @@ const getDomainName = (obj: string): string | undefined => {
3736
const getElementId = (attr: HTMLElement | string): string | undefined => {
3837
if (attr && (attr as HTMLElement).nodeName) {
3938
return (
40-
(attr as HTMLElement as any).uniqueId ||
39+
(attr as HTMLElement as any).uniqueId ??
4140
((attr as HTMLElement as any).uniqueId = generateIdToken())
4241
);
4342
}
@@ -51,19 +50,20 @@ const getElementId = (attr: HTMLElement | string): string | undefined => {
5150
element.uniqueId = attr as string;
5251
}
5352

54-
return element?.uniqueId || (attr as string);
55-
} catch (e) {
56-
return attr as string;
57-
}
53+
return element?.uniqueId ?? (attr as string);
54+
} catch {}
55+
56+
return attr as string;
5857
};
5958

6059
// Analyze video element
6160
const analyzeVideo = (
62-
target: HTMLElement | string | any,
61+
target: HTMLElement | string | undefined,
6362
): [HTMLElement | null, string | undefined, string] => {
6463
let videoTag: HTMLElement | null = null;
6564
if (target && (target as HTMLElement).nodeName !== undefined) {
66-
target = getElementId((videoTag = target as HTMLElement));
65+
videoTag = target as HTMLElement;
66+
target = getElementId(videoTag);
6767
} else {
6868
videoTag = document.querySelector(target as string) as HTMLElement;
6969
}
@@ -74,11 +74,11 @@ const analyzeVideo = (
7474

7575
// Identify or assign unique ID to an element
7676
const identifyElement = (target: HTMLElement | string): string | undefined => {
77-
let foundElement: Element | any = null;
77+
let foundElement: Element | null = null;
7878

7979
if (target && (target as HTMLElement).nodeName !== undefined) {
8080
return (
81-
(target as HTMLElement as any).elementId ||
81+
(target as HTMLElement as any).elementId ??
8282
((target as HTMLElement as any).elementId = generateRandomIdentifier()),
8383
(target as HTMLElement as any).elementId
8484
);
@@ -88,11 +88,11 @@ const identifyElement = (target: HTMLElement | string): string | undefined => {
8888
foundElement = document.querySelector(target as string);
8989
} catch {}
9090

91-
if (foundElement && !foundElement.elementId) {
92-
foundElement.elementId = target as string;
91+
if (foundElement && !(foundElement as any).elementId) {
92+
(foundElement as any).elementId = target as string;
9393
}
9494

95-
return foundElement?.elementId || (target as string);
95+
return (foundElement as any)?.elementId ?? (target as string);
9696
};
9797

9898
// Merge multiple objects, skipping undefined values
@@ -122,21 +122,17 @@ function formulateBeaconUrl(
122122
config: ActionableDataTypes,
123123
): string {
124124
const { beaconDomain } = config;
125-
const targetDomain = beaconDomain || "metrix.ws";
126-
const finalWorkspace = workspace || "collector";
127-
128-
if (config?.actionableData?.beaconCollectionDomain) {
129-
return `https://${config.actionableData.beaconCollectionDomain}`;
130-
}
125+
const targetDomain = beaconDomain ?? "metrix.ws";
126+
const finalWorkspace = workspace ?? "collector";
131127

132128
return `https://${finalWorkspace}.${targetDomain}`;
133129
}
134130

135131
// Check if Do Not Track is enabled
136132
function checkDoNotTrack(): boolean {
137133
const dntStatus =
138-
navigator.doNotTrack ||
139-
(window as any).doNotTrack ||
134+
navigator.doNotTrack ??
135+
(window as any).doNotTrack ??
140136
(navigator as any).msDoNotTrack;
141137

142138
return dntStatus === "1" || dntStatus === "yes";
@@ -221,8 +217,8 @@ function getRequestTimingDetails(event: any) {
221217
const checkNetworkBandwidth = (): string | undefined => {
222218
const connectionType = navigator as any;
223219
const connection =
224-
connectionType?.connection ||
225-
connectionType?.mozConnection ||
220+
connectionType?.connection ??
221+
connectionType?.mozConnection ??
226222
connectionType?.webkitConnection;
227223

228224
return connection?.type;

src/ConnectionHandler/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ const makeApiCall = async (
1111
failure: (arg0?: null | undefined, arg1?: string | null) => void,
1212
): Promise<void> => {
1313
try {
14-
if (
15-
destroyer &&
16-
navigator.sendBeacon &&
17-
navigator.sendBeacon(postcall, logData)
18-
) {
14+
if (destroyer && navigator.sendBeacon?.(postcall, logData)) {
1915
failure();
2016
}
2117

src/CookieMethod/index.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ const cookieName = "FastPixData";
55
// Get cookie from browser
66
const getCookie = function (name: string) {
77
const cookies = document.cookie.split(";");
8-
for (let i = 0; i < cookies.length; i++) {
9-
const cookie = cookies[i].trim();
8+
for (const cookie of cookies) {
9+
const trimmedCookie = cookie.trim();
1010

11-
if (cookie.startsWith(name + "=")) {
12-
const cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
11+
if (trimmedCookie.startsWith(name + "=")) {
12+
const cookieValue = decodeURIComponent(
13+
trimmedCookie.substring(name.length + 1),
14+
);
1315
const values: any = {};
1416
const keyValuePairs = cookieValue.split("&");
1517
keyValuePairs.forEach((pair) => {
@@ -33,7 +35,7 @@ const setCookie = (name: string, value: string, days: number): void => {
3335
// Get viewer data from the cookie
3436
const getViewerData = (): Record<string, any> => {
3537
const cookieValue = getCookie(cookieName);
36-
return cookieValue ? cookieValue : {};
38+
return cookieValue ?? {};
3739
};
3840

3941
// Update viewer data in the cookie

src/DataType/index.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,36 @@ interface OverrideableMetaData {
153153
device_name?: string;
154154
}
155155

156-
interface EventMetaData extends EventsInterface, UserCustomDataType {}
156+
interface EventMetaData extends EventsInterface, UserCustomDataType {
157+
debug: any;
158+
fetchStateData: () => {
159+
player_is_paused: any;
160+
player_width: any;
161+
player_height: any;
162+
player_autoplay_on: any;
163+
player_preload_on: boolean;
164+
player_is_fullscreen: boolean;
165+
video_source_height: any;
166+
video_source_width: any;
167+
video_source_url: any;
168+
video_source_domain: string | undefined;
169+
video_source_hostname: string | undefined;
170+
video_source_duration: number;
171+
video_poster_url: any;
172+
player_language_code: any;
173+
view_dropped_frame_count: any;
174+
};
175+
fetchPlayheadTime: () => number;
176+
data: any;
177+
automaticErrorTracking: any;
178+
Hls: any;
179+
hlsjs: any;
180+
}
157181

158182
interface EventData extends UserCustomDataType, OverrideableMetaData {}
159183

160184
interface ActionableDataTypes {
161-
beaconDomain?: string | undefined;
185+
beaconDomain?: string;
162186
errorConverter?: any;
163187
disablePlayheadRebufferTracking?: boolean;
164188
allowRebufferTracking?: boolean;

src/IdGenerationMethod/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ const generateIdToken: () => string = function () {
1212

1313
// Returns unique UUID
1414
const buildUUID: () => string = function () {
15-
1615
return uuidv4();
1716
};
1817

src/MonitorMetrics/ErrorManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export class ErrorManager {
3737
errorInfo.player_error_message ||
3838
errorInfo.player_error_context
3939
) {
40-
this.accuracy.data.player_error_code = errorInfo.player_error_code ?? "";
40+
this.accuracy.data.player_error_code =
41+
errorInfo.player_error_code ?? "";
4142
this.accuracy.data.player_error_message =
4243
errorInfo.player_error_message ?? "";
4344
this.accuracy.data.player_error_context =

0 commit comments

Comments
 (0)