unified-video-framework 1.4.248 → 1.4.250
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.
|
@@ -1115,11 +1115,15 @@ export class WebPlayer extends BasePlayer {
|
|
|
1115
1115
|
if (this.video && metadata.thumbnail) {
|
|
1116
1116
|
this.video.poster = metadata.thumbnail;
|
|
1117
1117
|
}
|
|
1118
|
+
|
|
1119
|
+
// Update metadata UI immediately with YouTube title and thumbnail
|
|
1120
|
+
this.updateMetadataUI();
|
|
1118
1121
|
|
|
1119
1122
|
// Create YouTube iframe player with custom controls integration
|
|
1120
1123
|
await this.createYouTubePlayer(videoId);
|
|
1121
1124
|
|
|
1122
1125
|
this.debugLog('✅ YouTube video loaded successfully');
|
|
1126
|
+
this.debugLog('YouTube video title:', metadata.title);
|
|
1123
1127
|
} catch (error) {
|
|
1124
1128
|
this.debugError('Failed to load YouTube video:', error);
|
|
1125
1129
|
throw new Error(`YouTube video loading failed: ${error}`);
|
|
@@ -1242,6 +1246,9 @@ export class WebPlayer extends BasePlayer {
|
|
|
1242
1246
|
if (this.config.muted) {
|
|
1243
1247
|
this.youtubePlayer.mute();
|
|
1244
1248
|
}
|
|
1249
|
+
|
|
1250
|
+
// Extract available YouTube qualities
|
|
1251
|
+
this.extractYouTubeAvailableQualities();
|
|
1245
1252
|
}
|
|
1246
1253
|
|
|
1247
1254
|
// Start time tracking
|
|
@@ -1337,6 +1344,114 @@ export class WebPlayer extends BasePlayer {
|
|
|
1337
1344
|
}
|
|
1338
1345
|
|
|
1339
1346
|
private youtubeTimeTrackingInterval: NodeJS.Timeout | null = null;
|
|
1347
|
+
private youtubeAvailableQualities: any[] = [];
|
|
1348
|
+
private youtubeCurrentQuality: any = null;
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* Extract available YouTube video qualities
|
|
1352
|
+
*/
|
|
1353
|
+
private extractYouTubeAvailableQualities(): void {
|
|
1354
|
+
if (!this.youtubePlayer) return;
|
|
1355
|
+
|
|
1356
|
+
try {
|
|
1357
|
+
const availableQualityLevels = this.youtubePlayer.getAvailableQualityLevels();
|
|
1358
|
+
this.debugLog('YouTube available quality levels:', availableQualityLevels);
|
|
1359
|
+
|
|
1360
|
+
// Map YouTube quality levels to standard labels
|
|
1361
|
+
const qualityMap: Record<string, any> = {
|
|
1362
|
+
'hd1080': { label: '1080p', value: 'hd1080', height: 1080 },
|
|
1363
|
+
'hd720': { label: '720p', value: 'hd720', height: 720 },
|
|
1364
|
+
'large': { label: '480p', value: 'large', height: 480 },
|
|
1365
|
+
'medium': { label: '360p', value: 'medium', height: 360 },
|
|
1366
|
+
'small': { label: '240p', value: 'small', height: 240 },
|
|
1367
|
+
'tiny': { label: '144p', value: 'tiny', height: 144 },
|
|
1368
|
+
'auto': { label: 'Auto', value: 'auto', height: 0 }
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1371
|
+
this.youtubeAvailableQualities = [];
|
|
1372
|
+
availableQualityLevels.forEach((qualityLevel: string) => {
|
|
1373
|
+
// Skip 'auto' from YouTube API - we'll add it explicitly
|
|
1374
|
+
if (qualityLevel === 'auto') return;
|
|
1375
|
+
if (qualityMap[qualityLevel]) {
|
|
1376
|
+
this.youtubeAvailableQualities.push(qualityMap[qualityLevel]);
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
// Always add auto quality option as the first item (exactly once)
|
|
1381
|
+
this.youtubeAvailableQualities.unshift({ label: 'Auto', value: 'auto', height: 0 });
|
|
1382
|
+
|
|
1383
|
+
this.debugLog('Mapped YouTube qualities:', this.youtubeAvailableQualities);
|
|
1384
|
+
|
|
1385
|
+
// Get current quality
|
|
1386
|
+
try {
|
|
1387
|
+
const currentQuality = this.youtubePlayer.getPlaybackQuality();
|
|
1388
|
+
this.youtubeCurrentQuality = qualityMap[currentQuality] || qualityMap['auto'];
|
|
1389
|
+
this.debugLog('Current YouTube quality:', this.youtubeCurrentQuality);
|
|
1390
|
+
} catch (e) {
|
|
1391
|
+
this.debugWarn('Could not get current YouTube quality:', e);
|
|
1392
|
+
this.youtubeCurrentQuality = qualityMap['auto'];
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// Update settings menu to show YouTube qualities
|
|
1396
|
+
this.updateSettingsMenu();
|
|
1397
|
+
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
this.debugWarn('Could not extract YouTube qualities:', error);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Set YouTube video quality
|
|
1405
|
+
*/
|
|
1406
|
+
private setYouTubeQuality(qualityLevel: string): void {
|
|
1407
|
+
if (!this.youtubePlayer) return;
|
|
1408
|
+
|
|
1409
|
+
try {
|
|
1410
|
+
const qualityMap: Record<string, any> = {
|
|
1411
|
+
'hd1080': { label: '1080p', value: 'hd1080', height: 1080 },
|
|
1412
|
+
'hd720': { label: '720p', value: 'hd720', height: 720 },
|
|
1413
|
+
'large': { label: '480p', value: 'large', height: 480 },
|
|
1414
|
+
'medium': { label: '360p', value: 'medium', height: 360 },
|
|
1415
|
+
'small': { label: '240p', value: 'small', height: 240 },
|
|
1416
|
+
'tiny': { label: '144p', value: 'tiny', height: 144 },
|
|
1417
|
+
'auto': { label: 'Auto', value: 'auto', height: 0 }
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
this.debugLog('📊 Attempting to set YouTube quality to:', qualityLevel);
|
|
1421
|
+
|
|
1422
|
+
// Try to set the quality
|
|
1423
|
+
this.youtubePlayer.setPlaybackQuality(qualityLevel);
|
|
1424
|
+
this.debugLog('✅ setPlaybackQuality called for:', qualityLevel);
|
|
1425
|
+
|
|
1426
|
+
// Verify quality was changed after a delay
|
|
1427
|
+
setTimeout(() => {
|
|
1428
|
+
try {
|
|
1429
|
+
const currentQuality = this.youtubePlayer.getPlaybackQuality();
|
|
1430
|
+
this.youtubeCurrentQuality = qualityMap[currentQuality] || qualityMap['auto'];
|
|
1431
|
+
|
|
1432
|
+
this.debugLog('📊 Current quality after set:', currentQuality, '(', this.youtubeCurrentQuality?.label, ')');
|
|
1433
|
+
|
|
1434
|
+
// Show notification with result
|
|
1435
|
+
if (currentQuality === qualityLevel) {
|
|
1436
|
+
this.showNotification(`Quality changed to ${qualityMap[currentQuality]?.label || 'requested quality'}`);
|
|
1437
|
+
this.debugLog('✅ Quality successfully changed to:', qualityLevel);
|
|
1438
|
+
} else {
|
|
1439
|
+
this.showNotification(`Quality set to ${qualityMap[currentQuality]?.label || currentQuality} (YouTube optimized)`);
|
|
1440
|
+
this.debugLog('⚠️ Requested quality:', qualityLevel, '| Actual quality:', currentQuality, '(YouTube may have optimized)');
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Update settings menu UI
|
|
1444
|
+
this.updateSettingsMenu();
|
|
1445
|
+
} catch (verifyError) {
|
|
1446
|
+
this.debugWarn('Could not verify YouTube quality:', verifyError);
|
|
1447
|
+
}
|
|
1448
|
+
}, 1000);
|
|
1449
|
+
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
this.debugWarn('❌ Could not set YouTube quality:', error);
|
|
1452
|
+
this.showNotification('Quality control limited on YouTube');
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1340
1455
|
|
|
1341
1456
|
private startYouTubeTimeTracking(): void {
|
|
1342
1457
|
if (this.youtubeTimeTrackingInterval) {
|
|
@@ -9071,12 +9186,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
9071
9186
|
private setQualityByLabel(quality: string): void {
|
|
9072
9187
|
// Handle YouTube player
|
|
9073
9188
|
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
9074
|
-
// YouTube quality
|
|
9075
|
-
this.
|
|
9076
|
-
|
|
9189
|
+
// Set YouTube quality directly
|
|
9190
|
+
this.setYouTubeQuality(quality);
|
|
9191
|
+
|
|
9192
|
+
// Update UI to reflect selection
|
|
9077
9193
|
document.querySelectorAll('.quality-option').forEach(option => {
|
|
9078
9194
|
option.classList.remove('active');
|
|
9079
|
-
if ((option as HTMLElement).dataset.quality ===
|
|
9195
|
+
if ((option as HTMLElement).dataset.quality === quality) {
|
|
9080
9196
|
option.classList.add('active');
|
|
9081
9197
|
}
|
|
9082
9198
|
});
|
|
@@ -9380,7 +9496,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
9380
9496
|
|
|
9381
9497
|
// Quality Accordion Section (only if enabled in config and qualities detected)
|
|
9382
9498
|
if (this.settingsConfig.quality && this.availableQualities.length > 0) {
|
|
9383
|
-
|
|
9499
|
+
// For YouTube, use youtubeCurrentQuality; otherwise use currentQuality
|
|
9500
|
+
const qualityForDisplay = this.youtubePlayer && this.youtubePlayerReady && this.youtubeCurrentQuality
|
|
9501
|
+
? this.youtubeCurrentQuality.value
|
|
9502
|
+
: this.currentQuality;
|
|
9503
|
+
const currentQuality = this.availableQualities.find(q => q.value === qualityForDisplay);
|
|
9384
9504
|
const currentQualityLabel = currentQuality ? currentQuality.label : 'Auto';
|
|
9385
9505
|
|
|
9386
9506
|
menuHTML += `
|
|
@@ -9400,7 +9520,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
9400
9520
|
<div class="uvf-accordion-content" data-section="quality">`;
|
|
9401
9521
|
|
|
9402
9522
|
this.availableQualities.forEach(quality => {
|
|
9403
|
-
|
|
9523
|
+
// For YouTube, compare against youtubeCurrentQuality
|
|
9524
|
+
const qualityValue = this.youtubePlayer && this.youtubePlayerReady && this.youtubeCurrentQuality
|
|
9525
|
+
? this.youtubeCurrentQuality.value
|
|
9526
|
+
: this.currentQuality;
|
|
9527
|
+
const isActive = quality.value === qualityValue ? 'active' : '';
|
|
9404
9528
|
const isPremium = this.isQualityPremium(quality);
|
|
9405
9529
|
const isLocked = isPremium && !this.isPremiumUser();
|
|
9406
9530
|
const qualityHeight = (quality as any).height || 0;
|
|
@@ -9468,10 +9592,20 @@ export class WebPlayer extends BasePlayer {
|
|
|
9468
9592
|
* Detect available video qualities from different sources
|
|
9469
9593
|
*/
|
|
9470
9594
|
private detectAvailableQualities(): void {
|
|
9471
|
-
|
|
9595
|
+
// Don't add default 'Auto' for YouTube - it's already included in youtubeAvailableQualities
|
|
9596
|
+
const isYouTube = this.youtubePlayer && this.youtubePlayerReady && this.youtubeAvailableQualities.length > 0;
|
|
9597
|
+
this.availableQualities = isYouTube ? [] : [{ value: 'auto', label: 'Auto' }];
|
|
9472
9598
|
let detectedQualities: Array<{ value: string; label: string; height?: number }> = [];
|
|
9473
9599
|
|
|
9474
|
-
|
|
9600
|
+
// YouTube qualities
|
|
9601
|
+
if (isYouTube) {
|
|
9602
|
+
detectedQualities = this.youtubeAvailableQualities.map(q => ({
|
|
9603
|
+
value: q.value,
|
|
9604
|
+
label: q.label,
|
|
9605
|
+
height: q.height
|
|
9606
|
+
}));
|
|
9607
|
+
this.debugLog('Using YouTube qualities:', detectedQualities);
|
|
9608
|
+
} else if (this.hls && this.hls.levels) {
|
|
9475
9609
|
// HLS qualities
|
|
9476
9610
|
this.hls.levels.forEach((level: any, index: number) => {
|
|
9477
9611
|
if (level.height) {
|
|
@@ -9843,6 +9977,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
9843
9977
|
private setQualityFromSettings(quality: string): void {
|
|
9844
9978
|
this.currentQuality = quality;
|
|
9845
9979
|
|
|
9980
|
+
// Handle YouTube quality
|
|
9981
|
+
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
9982
|
+
this.setYouTubeQuality(quality);
|
|
9983
|
+
this.debugLog(`YouTube quality set to ${quality}`);
|
|
9984
|
+
return;
|
|
9985
|
+
}
|
|
9986
|
+
|
|
9846
9987
|
if (quality === 'auto') {
|
|
9847
9988
|
// Enable auto quality with filter consideration
|
|
9848
9989
|
if (this.hls) {
|