unified-video-framework 1.4.373 → 1.4.374

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.
@@ -166,10 +166,13 @@ export class GoogleAdsManager {
166
166
  const companionAdSlots = this.config.companionAdSlots.map(slot => {
167
167
  return new google.ima.CompanionAdSelectionSettings();
168
168
  });
169
- adsRequest.setAdWillAutoPlay(true);
170
- adsRequest.setAdWillPlayMuted(false);
171
169
  }
172
170
 
171
+ // Chrome autoplay policy: ads must start muted for autoplay to work
172
+ // User can unmute after ad starts
173
+ adsRequest.setAdWillAutoPlay(true);
174
+ adsRequest.setAdWillPlayMuted(true); // Start muted for Chrome compatibility
175
+
173
176
  // Request ads
174
177
  this.adsLoader.requestAds(adsRequest);
175
178
  } catch (error) {
@@ -199,7 +202,8 @@ export class GoogleAdsManager {
199
202
  const adsRenderingSettings = new google.ima.AdsRenderingSettings();
200
203
  adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
201
204
  adsRenderingSettings.enablePreloading = true;
202
- adsRenderingSettings.mute = false; // Enable audio for ads
205
+ // Start muted for Chrome autoplay compatibility - user can unmute via button
206
+ adsRenderingSettings.mute = this.video.muted;
203
207
 
204
208
  // Get the ads manager
205
209
  this.adsManager = event.getAdsManager(this.video, adsRenderingSettings);
@@ -260,6 +264,15 @@ export class GoogleAdsManager {
260
264
  this.isAdPlaying = true;
261
265
  this.video.pause();
262
266
 
267
+ // Force ad container visibility and z-index
268
+ if (this.adContainer) {
269
+ this.adContainer.style.visibility = 'visible';
270
+ this.adContainer.style.opacity = '1';
271
+ this.adContainer.style.pointerEvents = 'auto';
272
+ this.adContainer.style.zIndex = '2147483647';
273
+ console.log('✅ Ad container visibility enforced');
274
+ }
275
+
263
276
  // Strict enforcement: Prevent video from playing during ads
264
277
  const preventPlayDuringAd = (e: Event) => {
265
278
  if (this.isAdPlaying) {
@@ -418,13 +431,26 @@ export class GoogleAdsManager {
418
431
  }
419
432
 
420
433
  /**
421
- * Resize ads
434
+ * Resize ads - with enhanced fullscreen support
422
435
  */
423
436
  resize(width: number, height: number, viewMode?: any): void {
424
437
  const google = (window as any).google;
425
438
  if (this.adsManager && google && google.ima) {
426
- // Use provided viewMode or default to NORMAL
427
439
  const mode = viewMode || google.ima.ViewMode.NORMAL;
440
+
441
+ console.log(`📐 Resizing ads: ${width}x${height}, ViewMode: ${mode === google.ima.ViewMode.FULLSCREEN ? 'FULLSCREEN' : 'NORMAL'}`);
442
+
443
+ // Force ad container dimensions in fullscreen
444
+ if (this.adContainer && mode === google.ima.ViewMode.FULLSCREEN) {
445
+ this.adContainer.style.position = 'fixed';
446
+ this.adContainer.style.top = '0';
447
+ this.adContainer.style.left = '0';
448
+ this.adContainer.style.width = `${width}px`;
449
+ this.adContainer.style.height = `${height}px`;
450
+ this.adContainer.style.zIndex = '2147483647';
451
+ console.log('✅ Ad container forced to fullscreen dimensions');
452
+ }
453
+
428
454
  this.adsManager.resize(width, height, mode);
429
455
  }
430
456
  }
@@ -531,9 +531,41 @@ export const WebPlayerView: React.FC<WebPlayerViewProps> = (props) => {
531
531
 
532
532
  // Google Ads state
533
533
  const adsManagerRef = useRef<GoogleAdsManager | null>(null);
534
- const adContainerRef = useRef<HTMLDivElement>(null);
534
+ const adContainerRef = useRef<HTMLDivElement | null>(null);
535
535
  const [isAdPlaying, setIsAdPlaying] = useState(false);
536
-
536
+
537
+ // Create ad container element programmatically
538
+ useEffect(() => {
539
+ if (!props.googleAds || adContainerRef.current) return;
540
+
541
+ const adContainer = document.createElement('div');
542
+ adContainer.className = 'uvf-ad-container';
543
+ adContainer.style.cssText = `
544
+ position: absolute;
545
+ top: 0;
546
+ left: 0;
547
+ right: 0;
548
+ bottom: 0;
549
+ z-index: 999999999;
550
+ pointer-events: none;
551
+ visibility: hidden;
552
+ opacity: 0;
553
+ transition: opacity 0.2s ease, visibility 0.2s ease;
554
+ `;
555
+
556
+ adContainerRef.current = adContainer;
557
+ console.log('✅ Ad container element created');
558
+ }, [props.googleAds]);
559
+
560
+ // Update ad container visibility when isAdPlaying changes
561
+ useEffect(() => {
562
+ if (!adContainerRef.current) return;
563
+
564
+ adContainerRef.current.style.pointerEvents = isAdPlaying ? 'auto' : 'none';
565
+ adContainerRef.current.style.visibility = isAdPlaying ? 'visible' : 'hidden';
566
+ adContainerRef.current.style.opacity = isAdPlaying ? '1' : '0';
567
+ }, [isAdPlaying]);
568
+
537
569
  /**
538
570
  * Generate ad chapter segments from googleAds cue points
539
571
  * Handles pre-roll (0), mid-rolls, and post-roll (-1)
@@ -1165,27 +1197,56 @@ export const WebPlayerView: React.FC<WebPlayerViewProps> = (props) => {
1165
1197
  if (props.onBuffering && typeof (player as any).on === 'function') {
1166
1198
  (player as any).on('onBuffering', props.onBuffering);
1167
1199
  }
1168
- if (props.onFullscreenChange && typeof (player as any).on === 'function') {
1200
+ if (typeof (player as any).on === 'function') {
1169
1201
  (player as any).on('onFullscreenChanged', (isFullscreen: boolean) => {
1202
+ console.log(`🔄 Fullscreen changed: ${isFullscreen}`);
1203
+
1204
+ // Force ad container positioning for fullscreen
1205
+ if (adContainerRef.current) {
1206
+ const adContainer = adContainerRef.current;
1207
+
1208
+ if (isFullscreen) {
1209
+ // Fullscreen: use fixed positioning
1210
+ adContainer.style.position = 'fixed';
1211
+ adContainer.style.top = '0';
1212
+ adContainer.style.left = '0';
1213
+ adContainer.style.width = '100vw';
1214
+ adContainer.style.height = '100vh';
1215
+ adContainer.style.zIndex = '2147483647';
1216
+ console.log('✅ Ad container: fullscreen positioning applied');
1217
+ } else {
1218
+ // Normal: use absolute positioning
1219
+ adContainer.style.position = 'absolute';
1220
+ adContainer.style.top = '0';
1221
+ adContainer.style.left = '0';
1222
+ adContainer.style.right = '0';
1223
+ adContainer.style.bottom = '0';
1224
+ adContainer.style.width = '';
1225
+ adContainer.style.height = '';
1226
+ adContainer.style.zIndex = '999999999';
1227
+ console.log('✅ Ad container: normal positioning restored');
1228
+ }
1229
+ }
1230
+
1170
1231
  // Resize Google Ads if active
1171
1232
  if (adsManagerRef.current) {
1172
1233
  const google = (window as any).google;
1173
1234
  if (google && google.ima) {
1174
- const container = containerRef.current;
1175
- const width = isFullscreen
1176
- ? window.screen.width
1177
- : (container?.clientWidth || window.innerWidth);
1178
- const height = isFullscreen
1179
- ? window.screen.height
1180
- : (container?.clientHeight || window.innerHeight);
1181
- const viewMode = isFullscreen
1182
- ? google.ima.ViewMode.FULLSCREEN
1235
+ const width = isFullscreen
1236
+ ? window.screen.width
1237
+ : (containerRef.current?.clientWidth || window.innerWidth);
1238
+ const height = isFullscreen
1239
+ ? window.screen.height
1240
+ : (containerRef.current?.clientHeight || window.innerHeight);
1241
+ const viewMode = isFullscreen
1242
+ ? google.ima.ViewMode.FULLSCREEN
1183
1243
  : google.ima.ViewMode.NORMAL;
1184
-
1244
+
1185
1245
  adsManagerRef.current.resize(width, height, viewMode);
1246
+ console.log(`✅ Ads resized: ${width}x${height}, ViewMode: ${viewMode === google.ima.ViewMode.FULLSCREEN ? 'FULLSCREEN' : 'NORMAL'}`);
1186
1247
  }
1187
1248
  }
1188
-
1249
+
1189
1250
  // Call user's fullscreen callback
1190
1251
  props.onFullscreenChange?.(isFullscreen);
1191
1252
  });
@@ -1271,18 +1332,47 @@ export const WebPlayerView: React.FC<WebPlayerViewProps> = (props) => {
1271
1332
 
1272
1333
  await adsManager.initialize();
1273
1334
  adsManagerRef.current = adsManager;
1274
-
1335
+
1275
1336
  console.log('Google Ads initialized successfully');
1276
-
1277
- // Initialize ad display container on first play
1337
+
1338
+ // Inject ad container into player wrapper (not as sibling)
1339
+ const playerWrapper = containerRef.current?.querySelector('.uvf-player-wrapper');
1340
+ if (playerWrapper && adContainerRef.current) {
1341
+ // Move ad container INSIDE player wrapper so it inherits fullscreen context
1342
+ playerWrapper.appendChild(adContainerRef.current);
1343
+ console.log('✅ Ad container injected into player wrapper');
1344
+ }
1345
+
1346
+ // Initialize ad display container on first user interaction
1347
+ // Chrome requires this to be called on a user gesture
1348
+ let adContainerInitialized = false;
1349
+
1350
+ const initAdsOnUserGesture = () => {
1351
+ if (!adContainerInitialized && adsManagerRef.current) {
1352
+ console.log('Initializing ad container on user gesture');
1353
+ try {
1354
+ adsManagerRef.current.initAdDisplayContainer();
1355
+ adContainerInitialized = true;
1356
+ } catch (err) {
1357
+ console.warn('Ad container init error:', err);
1358
+ }
1359
+ }
1360
+ };
1361
+
1278
1362
  const handleFirstPlay = () => {
1279
- if (adsManagerRef.current) {
1280
- adsManagerRef.current.initAdDisplayContainer();
1363
+ initAdsOnUserGesture();
1364
+ if (adsManagerRef.current && adContainerInitialized) {
1281
1365
  adsManagerRef.current.requestAds();
1282
1366
  }
1283
1367
  videoElement.removeEventListener('play', handleFirstPlay);
1368
+ videoElement.removeEventListener('click', initAdsOnUserGesture);
1369
+ adContainerRef.current?.removeEventListener('click', initAdsOnUserGesture);
1284
1370
  };
1371
+
1372
+ // Listen for both play and click events to ensure we catch user gesture
1285
1373
  videoElement.addEventListener('play', handleFirstPlay, { once: true });
1374
+ videoElement.addEventListener('click', initAdsOnUserGesture, { once: true });
1375
+ adContainerRef.current?.addEventListener('click', initAdsOnUserGesture, { once: true });
1286
1376
  } catch (adsError) {
1287
1377
  console.error('Failed to initialize Google Ads:', adsError);
1288
1378
  props.googleAds?.onAdError?.(adsError);
@@ -1619,29 +1709,13 @@ export const WebPlayerView: React.FC<WebPlayerViewProps> = (props) => {
1619
1709
  }}
1620
1710
  >
1621
1711
  {/* Video Player */}
1622
- <div
1623
- ref={containerRef}
1712
+ <div
1713
+ ref={containerRef}
1624
1714
  className={`uvf-responsive-container ${props.className || ''}`}
1625
1715
  style={responsiveStyle}
1626
1716
  />
1627
-
1628
- {/* Google Ads Container - positioned over the video player and controls */}
1629
- {props.googleAds && (
1630
- <div
1631
- ref={adContainerRef}
1632
- className="uvf-ad-container"
1633
- style={{
1634
- position: 'fixed',
1635
- top: 0,
1636
- left: 0,
1637
- right: 0,
1638
- bottom: 0,
1639
- zIndex: 2147483647, // Maximum z-index - ads must be on top of everything
1640
- pointerEvents: isAdPlaying ? 'auto' : 'none', // Allow interaction only when ad is playing
1641
- display: isAdPlaying ? 'block' : 'none', // Hide container when no ad
1642
- }}
1643
- />
1644
- )}
1717
+
1718
+ {/* Ad container will be programmatically injected into player wrapper */}
1645
1719
 
1646
1720
 
1647
1721
  {/* EPG Overlay - Full-screen glassmorphic overlay */}