@nikelroot/video-player 0.3.4 → 0.3.5

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/dist/index.cjs CHANGED
@@ -791,6 +791,11 @@ var getSource = (data) => {
791
791
  const responseUrl = isRecord(data.response) ? asText(data.response.url) : null;
792
792
  return responseUrl;
793
793
  };
794
+ var getErrorMessage = (error) => {
795
+ if (error instanceof Error) return error.message || error.name;
796
+ if (!isRecord(error)) return asText(error);
797
+ return asText(error.message) || asText(error.name);
798
+ };
794
799
  var addDetail = (details, label, value) => {
795
800
  const text = asText(value);
796
801
  if (!text) return;
@@ -808,14 +813,44 @@ var formatPlaybackErrorDetails = (error, data) => {
808
813
  addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430", error);
809
814
  }
810
815
  if (isRecord(data)) {
816
+ addDetail(details, "\u0412\u043B\u043E\u0436\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430", getErrorMessage(data.error));
811
817
  addDetail(details, "\u0422\u0438\u043F", data.type);
812
818
  addDetail(details, "\u0414\u0435\u0442\u0430\u043B\u0438", data.details);
813
819
  addDetail(details, "\u041F\u0440\u0438\u0447\u0438\u043D\u0430", data.reason);
814
820
  addDetail(details, "HTTP", getResponseSummary(data.response));
815
821
  addDetail(details, "\u0418\u0441\u0442\u043E\u0447\u043D\u0438\u043A", getSource(data));
822
+ addDetail(details, "init.mp4", data.initSegmentUrl);
823
+ addDetail(details, "MIME", data.mimeType);
824
+ addDetail(details, "MIME \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F", data.mimeSupported);
825
+ addDetail(details, "\u0411\u0443\u0444\u0435\u0440", data.sourceBufferName);
826
+ addDetail(details, "\u0412\u0435\u0440\u0441\u0438\u044F HLS.js", data.hlsVersion);
827
+ addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430", getErrorMessage(data.bufferError));
828
+ if (isRecord(data.bufferAddCodecError)) {
829
+ addDetail(details, "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 MIME", data.bufferAddCodecError.mimeType);
830
+ addDetail(details, "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 init.mp4", data.bufferAddCodecError.initSegmentUrl);
831
+ addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0431\u0443\u0444\u0435\u0440\u0430", getErrorMessage(data.bufferAddCodecError.error));
832
+ }
816
833
  }
817
834
  return details;
818
835
  };
836
+ var serializePlaybackErrorData = (data) => {
837
+ if (!isRecord(data) || !("error" in data)) return data;
838
+ const { error, ...rest } = data;
839
+ if (error instanceof Error) {
840
+ return { ...rest, error: { name: error.name, message: error.message } };
841
+ }
842
+ if (isRecord(error)) {
843
+ return {
844
+ ...rest,
845
+ error: {
846
+ ..."name" in error ? { name: error.name } : {},
847
+ ..."message" in error ? { message: error.message } : {},
848
+ ..."code" in error ? { code: error.code } : {}
849
+ }
850
+ };
851
+ }
852
+ return { ...rest, error };
853
+ };
819
854
 
820
855
  // src/VideoPlayer.tsx
821
856
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -979,6 +1014,7 @@ var VideoPlayerBase = (props, ref) => {
979
1014
  const netRetryCount = (0, import_react4.useRef)(0);
980
1015
  const mediaRecoverCount = (0, import_react4.useRef)(0);
981
1016
  const fatalReloadCount = (0, import_react4.useRef)(0);
1017
+ const lastBufferAddCodecFailure = (0, import_react4.useRef)(null);
982
1018
  const reloadTimer = (0, import_react4.useRef)(null);
983
1019
  const stalledNudgeTimer = (0, import_react4.useRef)(null);
984
1020
  const liveStabilityMode = (0, import_react4.useRef)(false);
@@ -1088,18 +1124,19 @@ var VideoPlayerBase = (props, ref) => {
1088
1124
  const reportError = (0, import_react4.useCallback)(
1089
1125
  (error, data, message = messages.defaultError) => {
1090
1126
  var _a, _b;
1091
- const details = formatPlaybackErrorDetails(error, data);
1127
+ const serializableData = serializePlaybackErrorData(data);
1128
+ const details = formatPlaybackErrorDetails(error, serializableData);
1092
1129
  const code = getPlaybackErrorCodeText(error);
1093
1130
  setNextPlaying(false);
1094
- setErrorState({ message, error, data, details });
1131
+ setErrorState({ message, error, data: serializableData, details });
1095
1132
  console.error("[VideoPlayer] playback error", {
1096
1133
  message,
1097
1134
  code,
1098
1135
  details,
1099
1136
  error,
1100
- data
1137
+ data: serializableData
1101
1138
  });
1102
- (_b = (_a = propsRef.current).onPlaybackError) == null ? void 0 : _b.call(_a, { error, data, message, details });
1139
+ (_b = (_a = propsRef.current).onPlaybackError) == null ? void 0 : _b.call(_a, { error, data: serializableData, message, details });
1103
1140
  },
1104
1141
  [messages.defaultError, setNextPlaying]
1105
1142
  );
@@ -1326,11 +1363,40 @@ var VideoPlayerBase = (props, ref) => {
1326
1363
  if (!video) return;
1327
1364
  const h = new HlsCtor(resolvedHlsConfig());
1328
1365
  hlsRef.current = h;
1366
+ let initSegmentUrl = null;
1329
1367
  const isStaleLoad = () => loadId !== sourceLoadId.current || hlsRef.current !== h || videoRef.current !== video;
1368
+ h.on(HlsCtor.Events.FRAG_LOADING, (_evt, data) => {
1369
+ if (!isStaleLoad() && data.frag.sn === "initSegment") initSegmentUrl = data.frag.url;
1370
+ });
1330
1371
  h.on(HlsCtor.Events.ERROR, (_evt, data) => {
1331
1372
  var _a2, _b2;
1332
1373
  if (isStaleLoad()) return;
1333
1374
  const { type: errorType, details, fatal } = data;
1375
+ if (details === HlsCtor.ErrorDetails.BUFFER_ADD_CODEC_ERROR) {
1376
+ const mediaSourceCtor = typeof window === "undefined" ? void 0 : window.ManagedMediaSource || window.MediaSource;
1377
+ const mimeSupported = data.mimeType && (mediaSourceCtor == null ? void 0 : mediaSourceCtor.isTypeSupported) ? mediaSourceCtor.isTypeSupported(data.mimeType) : null;
1378
+ const bufferError = data.error instanceof Error ? { name: data.error.name, message: data.error.message } : null;
1379
+ lastBufferAddCodecFailure.current = {
1380
+ sourceBufferName: data.sourceBufferName,
1381
+ mimeType: data.mimeType,
1382
+ mimeSupported,
1383
+ initSegmentUrl,
1384
+ error: bufferError
1385
+ };
1386
+ if (mimeSupported === false) {
1387
+ h.destroy();
1388
+ if (hlsRef.current === h) hlsRef.current = null;
1389
+ reportError(details, {
1390
+ type: errorType,
1391
+ details,
1392
+ fatal,
1393
+ src: videoSrc,
1394
+ hlsVersion: HlsCtor.version,
1395
+ ...lastBufferAddCodecFailure.current
1396
+ }, messages.unsupported);
1397
+ return;
1398
+ }
1399
+ }
1334
1400
  if (onAudioError(data)) return;
1335
1401
  if (!fatal && (details === HlsCtor.ErrorDetails.BUFFER_APPEND_ERROR || details === "bufferAppendingError")) return;
1336
1402
  if (!fatal) {
@@ -1404,7 +1470,7 @@ var VideoPlayerBase = (props, ref) => {
1404
1470
  }
1405
1471
  reportError(
1406
1472
  details,
1407
- data,
1473
+ lastBufferAddCodecFailure.current ? { ...data, bufferAddCodecError: lastBufferAddCodecFailure.current, src: videoSrc, hlsVersion: HlsCtor.version } : data,
1408
1474
  errorType === HlsCtor.ErrorTypes.MEDIA_ERROR ? messages.streamDecodeFailed : messages.streamLoadFailed
1409
1475
  );
1410
1476
  return;
@@ -1645,6 +1711,7 @@ var VideoPlayerBase = (props, ref) => {
1645
1711
  const loadId = sourceLoadId.current + 1;
1646
1712
  sourceLoadId.current = loadId;
1647
1713
  clearErrorState();
1714
+ lastBufferAddCodecFailure.current = null;
1648
1715
  fatalReloadCount.current = 0;
1649
1716
  netRetryCount.current = 0;
1650
1717
  mediaRecoverCount.current = 0;
package/dist/index.js CHANGED
@@ -762,6 +762,11 @@ var getSource = (data) => {
762
762
  const responseUrl = isRecord(data.response) ? asText(data.response.url) : null;
763
763
  return responseUrl;
764
764
  };
765
+ var getErrorMessage = (error) => {
766
+ if (error instanceof Error) return error.message || error.name;
767
+ if (!isRecord(error)) return asText(error);
768
+ return asText(error.message) || asText(error.name);
769
+ };
765
770
  var addDetail = (details, label, value) => {
766
771
  const text = asText(value);
767
772
  if (!text) return;
@@ -779,14 +784,44 @@ var formatPlaybackErrorDetails = (error, data) => {
779
784
  addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430", error);
780
785
  }
781
786
  if (isRecord(data)) {
787
+ addDetail(details, "\u0412\u043B\u043E\u0436\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430", getErrorMessage(data.error));
782
788
  addDetail(details, "\u0422\u0438\u043F", data.type);
783
789
  addDetail(details, "\u0414\u0435\u0442\u0430\u043B\u0438", data.details);
784
790
  addDetail(details, "\u041F\u0440\u0438\u0447\u0438\u043D\u0430", data.reason);
785
791
  addDetail(details, "HTTP", getResponseSummary(data.response));
786
792
  addDetail(details, "\u0418\u0441\u0442\u043E\u0447\u043D\u0438\u043A", getSource(data));
793
+ addDetail(details, "init.mp4", data.initSegmentUrl);
794
+ addDetail(details, "MIME", data.mimeType);
795
+ addDetail(details, "MIME \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F", data.mimeSupported);
796
+ addDetail(details, "\u0411\u0443\u0444\u0435\u0440", data.sourceBufferName);
797
+ addDetail(details, "\u0412\u0435\u0440\u0441\u0438\u044F HLS.js", data.hlsVersion);
798
+ addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430", getErrorMessage(data.bufferError));
799
+ if (isRecord(data.bufferAddCodecError)) {
800
+ addDetail(details, "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 MIME", data.bufferAddCodecError.mimeType);
801
+ addDetail(details, "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 init.mp4", data.bufferAddCodecError.initSegmentUrl);
802
+ addDetail(details, "\u041E\u0448\u0438\u0431\u043A\u0430 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0431\u0443\u0444\u0435\u0440\u0430", getErrorMessage(data.bufferAddCodecError.error));
803
+ }
787
804
  }
788
805
  return details;
789
806
  };
807
+ var serializePlaybackErrorData = (data) => {
808
+ if (!isRecord(data) || !("error" in data)) return data;
809
+ const { error, ...rest } = data;
810
+ if (error instanceof Error) {
811
+ return { ...rest, error: { name: error.name, message: error.message } };
812
+ }
813
+ if (isRecord(error)) {
814
+ return {
815
+ ...rest,
816
+ error: {
817
+ ..."name" in error ? { name: error.name } : {},
818
+ ..."message" in error ? { message: error.message } : {},
819
+ ..."code" in error ? { code: error.code } : {}
820
+ }
821
+ };
822
+ }
823
+ return { ...rest, error };
824
+ };
790
825
 
791
826
  // src/VideoPlayer.tsx
792
827
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -950,6 +985,7 @@ var VideoPlayerBase = (props, ref) => {
950
985
  const netRetryCount = useRef3(0);
951
986
  const mediaRecoverCount = useRef3(0);
952
987
  const fatalReloadCount = useRef3(0);
988
+ const lastBufferAddCodecFailure = useRef3(null);
953
989
  const reloadTimer = useRef3(null);
954
990
  const stalledNudgeTimer = useRef3(null);
955
991
  const liveStabilityMode = useRef3(false);
@@ -1059,18 +1095,19 @@ var VideoPlayerBase = (props, ref) => {
1059
1095
  const reportError = useCallback2(
1060
1096
  (error, data, message = messages.defaultError) => {
1061
1097
  var _a, _b;
1062
- const details = formatPlaybackErrorDetails(error, data);
1098
+ const serializableData = serializePlaybackErrorData(data);
1099
+ const details = formatPlaybackErrorDetails(error, serializableData);
1063
1100
  const code = getPlaybackErrorCodeText(error);
1064
1101
  setNextPlaying(false);
1065
- setErrorState({ message, error, data, details });
1102
+ setErrorState({ message, error, data: serializableData, details });
1066
1103
  console.error("[VideoPlayer] playback error", {
1067
1104
  message,
1068
1105
  code,
1069
1106
  details,
1070
1107
  error,
1071
- data
1108
+ data: serializableData
1072
1109
  });
1073
- (_b = (_a = propsRef.current).onPlaybackError) == null ? void 0 : _b.call(_a, { error, data, message, details });
1110
+ (_b = (_a = propsRef.current).onPlaybackError) == null ? void 0 : _b.call(_a, { error, data: serializableData, message, details });
1074
1111
  },
1075
1112
  [messages.defaultError, setNextPlaying]
1076
1113
  );
@@ -1297,11 +1334,40 @@ var VideoPlayerBase = (props, ref) => {
1297
1334
  if (!video) return;
1298
1335
  const h = new HlsCtor(resolvedHlsConfig());
1299
1336
  hlsRef.current = h;
1337
+ let initSegmentUrl = null;
1300
1338
  const isStaleLoad = () => loadId !== sourceLoadId.current || hlsRef.current !== h || videoRef.current !== video;
1339
+ h.on(HlsCtor.Events.FRAG_LOADING, (_evt, data) => {
1340
+ if (!isStaleLoad() && data.frag.sn === "initSegment") initSegmentUrl = data.frag.url;
1341
+ });
1301
1342
  h.on(HlsCtor.Events.ERROR, (_evt, data) => {
1302
1343
  var _a2, _b2;
1303
1344
  if (isStaleLoad()) return;
1304
1345
  const { type: errorType, details, fatal } = data;
1346
+ if (details === HlsCtor.ErrorDetails.BUFFER_ADD_CODEC_ERROR) {
1347
+ const mediaSourceCtor = typeof window === "undefined" ? void 0 : window.ManagedMediaSource || window.MediaSource;
1348
+ const mimeSupported = data.mimeType && (mediaSourceCtor == null ? void 0 : mediaSourceCtor.isTypeSupported) ? mediaSourceCtor.isTypeSupported(data.mimeType) : null;
1349
+ const bufferError = data.error instanceof Error ? { name: data.error.name, message: data.error.message } : null;
1350
+ lastBufferAddCodecFailure.current = {
1351
+ sourceBufferName: data.sourceBufferName,
1352
+ mimeType: data.mimeType,
1353
+ mimeSupported,
1354
+ initSegmentUrl,
1355
+ error: bufferError
1356
+ };
1357
+ if (mimeSupported === false) {
1358
+ h.destroy();
1359
+ if (hlsRef.current === h) hlsRef.current = null;
1360
+ reportError(details, {
1361
+ type: errorType,
1362
+ details,
1363
+ fatal,
1364
+ src: videoSrc,
1365
+ hlsVersion: HlsCtor.version,
1366
+ ...lastBufferAddCodecFailure.current
1367
+ }, messages.unsupported);
1368
+ return;
1369
+ }
1370
+ }
1305
1371
  if (onAudioError(data)) return;
1306
1372
  if (!fatal && (details === HlsCtor.ErrorDetails.BUFFER_APPEND_ERROR || details === "bufferAppendingError")) return;
1307
1373
  if (!fatal) {
@@ -1375,7 +1441,7 @@ var VideoPlayerBase = (props, ref) => {
1375
1441
  }
1376
1442
  reportError(
1377
1443
  details,
1378
- data,
1444
+ lastBufferAddCodecFailure.current ? { ...data, bufferAddCodecError: lastBufferAddCodecFailure.current, src: videoSrc, hlsVersion: HlsCtor.version } : data,
1379
1445
  errorType === HlsCtor.ErrorTypes.MEDIA_ERROR ? messages.streamDecodeFailed : messages.streamLoadFailed
1380
1446
  );
1381
1447
  return;
@@ -1616,6 +1682,7 @@ var VideoPlayerBase = (props, ref) => {
1616
1682
  const loadId = sourceLoadId.current + 1;
1617
1683
  sourceLoadId.current = loadId;
1618
1684
  clearErrorState();
1685
+ lastBufferAddCodecFailure.current = null;
1619
1686
  fatalReloadCount.current = 0;
1620
1687
  netRetryCount.current = 0;
1621
1688
  mediaRecoverCount.current = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikelroot/video-player",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Standalone React video player with HLS support.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,5 +48,5 @@
48
48
  "access": "public",
49
49
  "registry": "https://registry.npmjs.org/"
50
50
  },
51
- "gitHead": "7397c01305b40debca1523d771784247db250de0"
51
+ "gitHead": "3bc5c054756e591f2ba73678de16dd1dfc0bb80f"
52
52
  }