@applicaster/zapp-react-native-utils 13.0.8-alpha.1940580104 → 13.0.8-alpha.4487353250
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/package.json +2 -2
- package/playerUtils/PlayerTTS/PlayerTTS.ts +159 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "13.0.8-alpha.
|
|
3
|
+
"version": "13.0.8-alpha.4487353250",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "13.0.8-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "13.0.8-alpha.4487353250",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -1,12 +1,40 @@
|
|
|
1
|
-
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
2
1
|
import uuidv4 from "uuid/v4";
|
|
3
|
-
import {
|
|
2
|
+
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
3
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
4
|
+
import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
|
|
5
|
+
|
|
6
|
+
const { log_debug, log_error } = createLogger({
|
|
7
|
+
subsystem: "Player",
|
|
8
|
+
category: "PlayerTTS",
|
|
9
|
+
});
|
|
4
10
|
|
|
5
11
|
enum SEEK_DIRECTION {
|
|
6
12
|
FORWARD = "forward",
|
|
7
13
|
REWIND = "back",
|
|
8
14
|
}
|
|
9
15
|
|
|
16
|
+
const hasPrerollAds = (entry: ZappEntry): boolean => {
|
|
17
|
+
const videoAds = entry?.extensions?.video_ads;
|
|
18
|
+
|
|
19
|
+
if (!videoAds) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If it's a string (VMAP URL), assume it might have preroll
|
|
24
|
+
if (typeof videoAds === "string") {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If it's an array, check for preroll offset
|
|
29
|
+
if (Array.isArray(videoAds)) {
|
|
30
|
+
return videoAds.some(
|
|
31
|
+
(ad: ZappVideoAdExtension) => ad.offset === "preroll" || ad.offset === 0
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return false;
|
|
36
|
+
};
|
|
37
|
+
|
|
10
38
|
export class PlayerTTS {
|
|
11
39
|
private player: Player;
|
|
12
40
|
private accessibilityManager: AccessibilityManager;
|
|
@@ -14,11 +42,20 @@ export class PlayerTTS {
|
|
|
14
42
|
private isSeeking: boolean = false;
|
|
15
43
|
private listenerId: string;
|
|
16
44
|
private isInitialPlayerOpen: boolean = true;
|
|
45
|
+
private isPrerollActive: boolean = false;
|
|
46
|
+
private hasPrerollAds: boolean = false; // Track if preroll ads are expected
|
|
17
47
|
|
|
18
48
|
constructor(player: Player, accessibilityManager: AccessibilityManager) {
|
|
19
49
|
this.player = player;
|
|
20
50
|
this.accessibilityManager = accessibilityManager;
|
|
21
51
|
this.listenerId = `player-tts-${uuidv4()}`;
|
|
52
|
+
this.hasPrerollAds = hasPrerollAds(player.entry);
|
|
53
|
+
|
|
54
|
+
log_debug("PlayerTTS initialized", {
|
|
55
|
+
hasPrerollAds: this.hasPrerollAds,
|
|
56
|
+
listenerId: this.listenerId,
|
|
57
|
+
entryTitle: player.entry.title,
|
|
58
|
+
});
|
|
22
59
|
}
|
|
23
60
|
|
|
24
61
|
private numberToWords(num: number): string {
|
|
@@ -64,9 +101,7 @@ export class PlayerTTS {
|
|
|
64
101
|
const ten = Math.floor(num / 10);
|
|
65
102
|
const one = num % 10;
|
|
66
103
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return `${tens[ten]} ${ones[one]}`;
|
|
104
|
+
return one === 0 ? tens[ten] : `${tens[ten]} ${ones[one]}`;
|
|
70
105
|
}
|
|
71
106
|
|
|
72
107
|
private secondsToTime(
|
|
@@ -79,17 +114,19 @@ export class PlayerTTS {
|
|
|
79
114
|
const remainingSeconds = Math.floor(seconds % 60);
|
|
80
115
|
|
|
81
116
|
if (format === "standard") {
|
|
82
|
-
|
|
83
|
-
if (remainingSeconds === 0) return "0";
|
|
117
|
+
const parts = [];
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
if (minutes > 0) {
|
|
120
|
+
parts.push(`${minutes} minute${minutes !== 1 ? "s" : ""}`);
|
|
86
121
|
}
|
|
87
122
|
|
|
88
|
-
if (remainingSeconds
|
|
89
|
-
|
|
123
|
+
if (remainingSeconds > 0) {
|
|
124
|
+
parts.push(
|
|
125
|
+
`${remainingSeconds} second${remainingSeconds !== 1 ? "s" : ""}`
|
|
126
|
+
);
|
|
90
127
|
}
|
|
91
128
|
|
|
92
|
-
return
|
|
129
|
+
return parts.length > 0 ? parts.join(" ") : "0";
|
|
93
130
|
} else {
|
|
94
131
|
if (minutes === 0) {
|
|
95
132
|
if (remainingSeconds === 0) return "zero";
|
|
@@ -113,10 +150,6 @@ export class PlayerTTS {
|
|
|
113
150
|
}
|
|
114
151
|
}
|
|
115
152
|
|
|
116
|
-
private announceLoading = () => {
|
|
117
|
-
this.accessibilityManager.addHeading("Loading");
|
|
118
|
-
};
|
|
119
|
-
|
|
120
153
|
private announcePause = () => {
|
|
121
154
|
if (!this.isSeeking) {
|
|
122
155
|
this.accessibilityManager.addHeading(
|
|
@@ -125,29 +158,84 @@ export class PlayerTTS {
|
|
|
125
158
|
}
|
|
126
159
|
};
|
|
127
160
|
|
|
161
|
+
private announceContentStart(
|
|
162
|
+
options: {
|
|
163
|
+
currentTime?: number;
|
|
164
|
+
duration?: number;
|
|
165
|
+
useReadText?: boolean;
|
|
166
|
+
} = {}
|
|
167
|
+
): void {
|
|
168
|
+
const { currentTime, duration, useReadText = false } = options;
|
|
169
|
+
const state = this.player.playerState;
|
|
170
|
+
|
|
171
|
+
const timeRemaining =
|
|
172
|
+
(duration || state?.contentDuration || 0) -
|
|
173
|
+
(currentTime || state?.contentPosition || 0);
|
|
174
|
+
|
|
175
|
+
const title = (this.player.entry.title as string) || "";
|
|
176
|
+
const summary = (this.player.entry.summary as string) || "";
|
|
177
|
+
|
|
178
|
+
log_debug("Announcing content start", {
|
|
179
|
+
title,
|
|
180
|
+
currentTime: currentTime || state?.contentPosition || 0,
|
|
181
|
+
duration: duration || state?.contentDuration || 0,
|
|
182
|
+
timeRemaining,
|
|
183
|
+
useReadText,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
this.accessibilityManager.addHeading(`Playing - ${title}`);
|
|
187
|
+
if (summary) this.accessibilityManager.addHeading(summary);
|
|
188
|
+
|
|
189
|
+
this.accessibilityManager.addHeading(
|
|
190
|
+
`Playing from ${this.secondsToTime(currentTime || state?.contentPosition || 0, "standard")}`
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const remainingText = `${this.secondsToTime(Math.max(0, Math.floor(timeRemaining)), "standard")} remaining.`;
|
|
194
|
+
|
|
195
|
+
if (useReadText) {
|
|
196
|
+
this.accessibilityManager.readText({ text: remainingText });
|
|
197
|
+
} else {
|
|
198
|
+
this.accessibilityManager.addHeading(remainingText);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.accessibilityManager.setInitialPlayerAnnouncementReady();
|
|
202
|
+
this.isInitialPlayerOpen = false;
|
|
203
|
+
}
|
|
204
|
+
|
|
128
205
|
private announceBufferComplete = (event: any) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
206
|
+
// If preroll ads are expected, wait for them to finish before announcing content
|
|
207
|
+
if (this.hasPrerollAds && this.isInitialPlayerOpen) {
|
|
208
|
+
log_debug("Waiting for preroll ads to finish", {
|
|
209
|
+
hasPrerollAds: this.hasPrerollAds,
|
|
210
|
+
isInitialPlayerOpen: this.isInitialPlayerOpen,
|
|
211
|
+
});
|
|
135
212
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
139
215
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
216
|
+
// Gate content announcement until preroll finishes
|
|
217
|
+
if (this.isInitialPlayerOpen && !this.isPrerollActive) {
|
|
218
|
+
log_debug("Buffer complete - announcing content", {
|
|
219
|
+
currentTime: event.currentTime,
|
|
220
|
+
duration: event.duration,
|
|
221
|
+
isPrerollActive: this.isPrerollActive,
|
|
222
|
+
});
|
|
143
223
|
|
|
144
|
-
this.
|
|
145
|
-
|
|
224
|
+
this.announceContentStart({
|
|
225
|
+
currentTime: event.currentTime,
|
|
226
|
+
duration: event.duration,
|
|
227
|
+
});
|
|
146
228
|
}
|
|
147
229
|
};
|
|
148
230
|
|
|
149
231
|
private announceResume = () => {
|
|
150
232
|
if (!this.isSeeking && !this.isInitialPlayerOpen) {
|
|
233
|
+
log_debug("Player resumed", {
|
|
234
|
+
contentPosition: this.player.playerState.contentPosition,
|
|
235
|
+
isSeeking: this.isSeeking,
|
|
236
|
+
isInitialPlayerOpen: this.isInitialPlayerOpen,
|
|
237
|
+
});
|
|
238
|
+
|
|
151
239
|
this.accessibilityManager.addHeading(
|
|
152
240
|
`Playing - ${this.secondsToTime(this.player.playerState.contentPosition, "standard")}`
|
|
153
241
|
);
|
|
@@ -171,6 +259,13 @@ export class PlayerTTS {
|
|
|
171
259
|
Math.abs(event.currentTime - this.seekStartPosition)
|
|
172
260
|
);
|
|
173
261
|
|
|
262
|
+
log_debug("Seek completed", {
|
|
263
|
+
seekDirection,
|
|
264
|
+
seekAmount,
|
|
265
|
+
fromPosition: this.seekStartPosition,
|
|
266
|
+
toPosition: event.currentTime,
|
|
267
|
+
});
|
|
268
|
+
|
|
174
269
|
this.accessibilityManager.readText({
|
|
175
270
|
text: `Skipped ${seekDirection} ${this.secondsToTime(seekAmount, "standard")}`,
|
|
176
271
|
});
|
|
@@ -182,15 +277,24 @@ export class PlayerTTS {
|
|
|
182
277
|
};
|
|
183
278
|
|
|
184
279
|
private handleSeekStart = () => {
|
|
280
|
+
log_debug("Seek started");
|
|
185
281
|
this.isSeeking = true;
|
|
186
282
|
};
|
|
187
283
|
|
|
188
284
|
private handlePlayerClose = () => {
|
|
285
|
+
log_debug("Player closed - resetting state");
|
|
189
286
|
this.isInitialPlayerOpen = true;
|
|
190
287
|
this.accessibilityManager.resetInitialPlayerAnnouncementReady();
|
|
191
288
|
};
|
|
192
289
|
|
|
193
290
|
private announceAdBegin = (event: any) => {
|
|
291
|
+
this.isPrerollActive = true;
|
|
292
|
+
|
|
293
|
+
log_debug("Ad started", {
|
|
294
|
+
adDuration: event?.ad?.data?.duration,
|
|
295
|
+
isPrerollActive: this.isPrerollActive,
|
|
296
|
+
});
|
|
297
|
+
|
|
194
298
|
if (event?.ad?.data?.duration) {
|
|
195
299
|
this.accessibilityManager.readText({
|
|
196
300
|
text: `Sponsored. Ends in ${this.secondsToTime(event.ad.data.duration, "standard")}`,
|
|
@@ -198,15 +302,34 @@ export class PlayerTTS {
|
|
|
198
302
|
}
|
|
199
303
|
};
|
|
200
304
|
|
|
305
|
+
private handleAdEnd = (_event: any) => {
|
|
306
|
+
this.isPrerollActive = false;
|
|
307
|
+
|
|
308
|
+
log_debug("Ad ended", {
|
|
309
|
+
isPrerollActive: this.isPrerollActive,
|
|
310
|
+
isInitialPlayerOpen: this.isInitialPlayerOpen,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// If initial entry still pending, trigger content announcement using latest player state
|
|
314
|
+
if (this.isInitialPlayerOpen) {
|
|
315
|
+
this.announceContentStart({ useReadText: true });
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
201
319
|
public init(): () => void {
|
|
202
320
|
if (!this.player) {
|
|
321
|
+
log_error("Failed to initialize PlayerTTS - no player provided");
|
|
322
|
+
|
|
203
323
|
return () => {};
|
|
204
324
|
}
|
|
205
325
|
|
|
326
|
+
log_debug("Initializing PlayerTTS listeners", {
|
|
327
|
+
listenerId: this.listenerId,
|
|
328
|
+
});
|
|
329
|
+
|
|
206
330
|
return this.player.addListener({
|
|
207
331
|
id: this.listenerId,
|
|
208
332
|
listener: {
|
|
209
|
-
onBufferStart: this.announceLoading,
|
|
210
333
|
onBufferComplete: this.announceBufferComplete,
|
|
211
334
|
onPlayerResume: this.announceResume,
|
|
212
335
|
onPlayerPause: this.announcePause,
|
|
@@ -215,11 +338,17 @@ export class PlayerTTS {
|
|
|
215
338
|
onPlayerSeekComplete: this.handleSeekComplete,
|
|
216
339
|
onPlayerClose: this.handlePlayerClose,
|
|
217
340
|
onAdBegin: this.announceAdBegin,
|
|
341
|
+
onAdEnd: this.handleAdEnd,
|
|
342
|
+
onAdBreakEnd: this.handleAdEnd,
|
|
218
343
|
},
|
|
219
344
|
});
|
|
220
345
|
}
|
|
221
346
|
|
|
222
347
|
public destroy(): void {
|
|
348
|
+
log_debug("Destroying PlayerTTS", {
|
|
349
|
+
listenerId: this.listenerId,
|
|
350
|
+
});
|
|
351
|
+
|
|
223
352
|
if (this.player) {
|
|
224
353
|
this.player.removeListener(this.listenerId);
|
|
225
354
|
}
|