unified-video-framework 1.4.437 → 1.4.438

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.
@@ -172,6 +172,8 @@ export class WebPlayer extends BasePlayer {
172
172
  private currentRetryAttempt: number = 0;
173
173
  private lastFailedUrl: string = ''; // Track last failed URL to avoid duplicate error handling
174
174
  private isFallbackPosterMode: boolean = false; // True when showing fallback poster (no playable sources)
175
+ private hlsErrorRetryCount: number = 0; // Track HLS error recovery attempts
176
+ private readonly MAX_HLS_ERROR_RETRIES: number = 3; // Max HLS recovery attempts before fallback
175
177
 
176
178
  // Live stream detection
177
179
  private lastDuration: number = 0; // Track duration changes to detect live streams
@@ -727,6 +729,7 @@ export class WebPlayer extends BasePlayer {
727
729
  this.currentRetryAttempt = 0;
728
730
  this.lastFailedUrl = '';
729
731
  this.isFallbackPosterMode = false; // Reset fallback poster mode
732
+ this.hlsErrorRetryCount = 0; // Reset HLS error retry count
730
733
 
731
734
  // Clean up previous instances
732
735
  await this.cleanup();
@@ -1122,6 +1125,9 @@ export class WebPlayer extends BasePlayer {
1122
1125
  this.hls.attachMedia(this.video);
1123
1126
 
1124
1127
  this.hls.on(window.Hls.Events.MANIFEST_PARSED, (event: any, data: any) => {
1128
+ // Reset HLS error retry count on successful manifest load
1129
+ this.hlsErrorRetryCount = 0;
1130
+
1125
1131
  // Extract quality levels
1126
1132
  this.qualities = data.levels.map((level: any, index: number) => ({
1127
1133
  height: level.height,
@@ -1164,27 +1170,101 @@ export class WebPlayer extends BasePlayer {
1164
1170
  }
1165
1171
  }
1166
1172
 
1167
- private handleHLSError(data: any): void {
1173
+ private async handleHLSError(data: any): Promise<void> {
1168
1174
  const Hls = window.Hls;
1175
+
1176
+ this.debugLog(`🔴 HLS Error: type=${data.type}, details=${data.details}, fatal=${data.fatal}`);
1177
+
1178
+ // Check if we've exceeded max retry attempts
1179
+ if (this.hlsErrorRetryCount >= this.MAX_HLS_ERROR_RETRIES) {
1180
+ this.debugLog(`🔴 HLS max retries (${this.MAX_HLS_ERROR_RETRIES}) exceeded, triggering fallback`);
1181
+ this.hls?.destroy();
1182
+ this.hls = null;
1183
+
1184
+ // Try fallback sources
1185
+ const fallbackLoaded = await this.tryFallbackSource({
1186
+ code: 'HLS_ERROR',
1187
+ message: data.details,
1188
+ type: data.type,
1189
+ fatal: true,
1190
+ details: data
1191
+ });
1192
+
1193
+ if (!fallbackLoaded) {
1194
+ this.handleError({
1195
+ code: 'HLS_ERROR',
1196
+ message: `HLS stream failed after ${this.MAX_HLS_ERROR_RETRIES} retries: ${data.details}`,
1197
+ type: 'media',
1198
+ fatal: true,
1199
+ details: data
1200
+ });
1201
+ }
1202
+ return;
1203
+ }
1204
+
1169
1205
  switch (data.type) {
1170
1206
  case Hls.ErrorTypes.NETWORK_ERROR:
1171
- console.error('Fatal network error, trying to recover');
1172
- this.hls.startLoad();
1207
+ this.hlsErrorRetryCount++;
1208
+ this.debugLog(`🔴 Fatal network error (attempt ${this.hlsErrorRetryCount}/${this.MAX_HLS_ERROR_RETRIES}), trying to recover`);
1209
+
1210
+ // For manifest errors (like 404), recovery won't help - go straight to fallback
1211
+ if (data.details === 'manifestLoadError' || data.details === 'manifestParsingError') {
1212
+ this.debugLog(`🔴 Manifest error detected (${data.details}), skipping recovery - triggering fallback`);
1213
+ this.hls?.destroy();
1214
+ this.hls = null;
1215
+
1216
+ const fallbackLoaded = await this.tryFallbackSource({
1217
+ code: 'HLS_MANIFEST_ERROR',
1218
+ message: data.details,
1219
+ type: 'network',
1220
+ fatal: true,
1221
+ details: data
1222
+ });
1223
+
1224
+ if (!fallbackLoaded) {
1225
+ this.handleError({
1226
+ code: 'HLS_MANIFEST_ERROR',
1227
+ message: `Failed to load HLS manifest: ${data.details}`,
1228
+ type: 'media',
1229
+ fatal: true,
1230
+ details: data
1231
+ });
1232
+ }
1233
+ } else {
1234
+ // For other network errors, try recovery
1235
+ this.hls?.startLoad();
1236
+ }
1173
1237
  break;
1238
+
1174
1239
  case Hls.ErrorTypes.MEDIA_ERROR:
1175
- console.error('Fatal media error, trying to recover');
1176
- this.hls.recoverMediaError();
1240
+ this.hlsErrorRetryCount++;
1241
+ this.debugLog(`🔴 Fatal media error (attempt ${this.hlsErrorRetryCount}/${this.MAX_HLS_ERROR_RETRIES}), trying to recover`);
1242
+ this.hls?.recoverMediaError();
1177
1243
  break;
1244
+
1178
1245
  default:
1179
- console.error('Fatal error, cannot recover');
1180
- this.handleError({
1246
+ this.debugLog(`🔴 Fatal unrecoverable HLS error: ${data.details}`);
1247
+ this.hls?.destroy();
1248
+ this.hls = null;
1249
+
1250
+ // Try fallback sources for unrecoverable errors
1251
+ const fallbackLoaded = await this.tryFallbackSource({
1181
1252
  code: 'HLS_ERROR',
1182
1253
  message: data.details,
1183
1254
  type: 'media',
1184
1255
  fatal: true,
1185
1256
  details: data
1186
1257
  });
1187
- this.hls.destroy();
1258
+
1259
+ if (!fallbackLoaded) {
1260
+ this.handleError({
1261
+ code: 'HLS_ERROR',
1262
+ message: data.details,
1263
+ type: 'media',
1264
+ fatal: true,
1265
+ details: data
1266
+ });
1267
+ }
1188
1268
  break;
1189
1269
  }
1190
1270
  }