@nikelroot/video-player 0.3.3 → 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");
@@ -958,6 +993,7 @@ var VideoPlayerBase = (props, ref) => {
958
993
  videoOnlySrc,
959
994
  audioRanges,
960
995
  onAudioFallbackChange,
996
+ afterScroll,
961
997
  ...videoProps
962
998
  } = props;
963
999
  const primarySrc = rawVideoSrc.replaceAll(" ", "%20").replaceAll("#", "%23");
@@ -978,6 +1014,7 @@ var VideoPlayerBase = (props, ref) => {
978
1014
  const netRetryCount = (0, import_react4.useRef)(0);
979
1015
  const mediaRecoverCount = (0, import_react4.useRef)(0);
980
1016
  const fatalReloadCount = (0, import_react4.useRef)(0);
1017
+ const lastBufferAddCodecFailure = (0, import_react4.useRef)(null);
981
1018
  const reloadTimer = (0, import_react4.useRef)(null);
982
1019
  const stalledNudgeTimer = (0, import_react4.useRef)(null);
983
1020
  const liveStabilityMode = (0, import_react4.useRef)(false);
@@ -1087,18 +1124,19 @@ var VideoPlayerBase = (props, ref) => {
1087
1124
  const reportError = (0, import_react4.useCallback)(
1088
1125
  (error, data, message = messages.defaultError) => {
1089
1126
  var _a, _b;
1090
- const details = formatPlaybackErrorDetails(error, data);
1127
+ const serializableData = serializePlaybackErrorData(data);
1128
+ const details = formatPlaybackErrorDetails(error, serializableData);
1091
1129
  const code = getPlaybackErrorCodeText(error);
1092
1130
  setNextPlaying(false);
1093
- setErrorState({ message, error, data, details });
1131
+ setErrorState({ message, error, data: serializableData, details });
1094
1132
  console.error("[VideoPlayer] playback error", {
1095
1133
  message,
1096
1134
  code,
1097
1135
  details,
1098
1136
  error,
1099
- data
1137
+ data: serializableData
1100
1138
  });
1101
- (_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 });
1102
1140
  },
1103
1141
  [messages.defaultError, setNextPlaying]
1104
1142
  );
@@ -1217,6 +1255,7 @@ var VideoPlayerBase = (props, ref) => {
1217
1255
  block: "center",
1218
1256
  inline: "nearest"
1219
1257
  });
1258
+ afterScroll && afterScroll();
1220
1259
  }
1221
1260
  }
1222
1261
  }, [
@@ -1324,11 +1363,40 @@ var VideoPlayerBase = (props, ref) => {
1324
1363
  if (!video) return;
1325
1364
  const h = new HlsCtor(resolvedHlsConfig());
1326
1365
  hlsRef.current = h;
1366
+ let initSegmentUrl = null;
1327
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
+ });
1328
1371
  h.on(HlsCtor.Events.ERROR, (_evt, data) => {
1329
1372
  var _a2, _b2;
1330
1373
  if (isStaleLoad()) return;
1331
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
+ }
1332
1400
  if (onAudioError(data)) return;
1333
1401
  if (!fatal && (details === HlsCtor.ErrorDetails.BUFFER_APPEND_ERROR || details === "bufferAppendingError")) return;
1334
1402
  if (!fatal) {
@@ -1402,7 +1470,7 @@ var VideoPlayerBase = (props, ref) => {
1402
1470
  }
1403
1471
  reportError(
1404
1472
  details,
1405
- data,
1473
+ lastBufferAddCodecFailure.current ? { ...data, bufferAddCodecError: lastBufferAddCodecFailure.current, src: videoSrc, hlsVersion: HlsCtor.version } : data,
1406
1474
  errorType === HlsCtor.ErrorTypes.MEDIA_ERROR ? messages.streamDecodeFailed : messages.streamLoadFailed
1407
1475
  );
1408
1476
  return;
@@ -1643,6 +1711,7 @@ var VideoPlayerBase = (props, ref) => {
1643
1711
  const loadId = sourceLoadId.current + 1;
1644
1712
  sourceLoadId.current = loadId;
1645
1713
  clearErrorState();
1714
+ lastBufferAddCodecFailure.current = null;
1646
1715
  fatalReloadCount.current = 0;
1647
1716
  netRetryCount.current = 0;
1648
1717
  mediaRecoverCount.current = 0;
package/dist/index.d.cts CHANGED
@@ -90,6 +90,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
90
90
  onPointerUp?: PointerHandler;
91
91
  onPointerCancel?: PointerHandler;
92
92
  accentColor?: string;
93
+ afterScroll?: () => void;
93
94
  }
94
95
  declare function hasNativeHlsSupport(): boolean;
95
96
  declare const VideoPlayer: React.NamedExoticComponent<VideoPlayerProps & React.RefAttributes<VideoPlayerHandle>>;
package/dist/index.d.ts CHANGED
@@ -90,6 +90,7 @@ interface VideoPlayerProps extends Omit<React.VideoHTMLAttributes<HTMLVideoEleme
90
90
  onPointerUp?: PointerHandler;
91
91
  onPointerCancel?: PointerHandler;
92
92
  accentColor?: string;
93
+ afterScroll?: () => void;
93
94
  }
94
95
  declare function hasNativeHlsSupport(): boolean;
95
96
  declare const VideoPlayer: React.NamedExoticComponent<VideoPlayerProps & React.RefAttributes<VideoPlayerHandle>>;
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";
@@ -929,6 +964,7 @@ var VideoPlayerBase = (props, ref) => {
929
964
  videoOnlySrc,
930
965
  audioRanges,
931
966
  onAudioFallbackChange,
967
+ afterScroll,
932
968
  ...videoProps
933
969
  } = props;
934
970
  const primarySrc = rawVideoSrc.replaceAll(" ", "%20").replaceAll("#", "%23");
@@ -949,6 +985,7 @@ var VideoPlayerBase = (props, ref) => {
949
985
  const netRetryCount = useRef3(0);
950
986
  const mediaRecoverCount = useRef3(0);
951
987
  const fatalReloadCount = useRef3(0);
988
+ const lastBufferAddCodecFailure = useRef3(null);
952
989
  const reloadTimer = useRef3(null);
953
990
  const stalledNudgeTimer = useRef3(null);
954
991
  const liveStabilityMode = useRef3(false);
@@ -1058,18 +1095,19 @@ var VideoPlayerBase = (props, ref) => {
1058
1095
  const reportError = useCallback2(
1059
1096
  (error, data, message = messages.defaultError) => {
1060
1097
  var _a, _b;
1061
- const details = formatPlaybackErrorDetails(error, data);
1098
+ const serializableData = serializePlaybackErrorData(data);
1099
+ const details = formatPlaybackErrorDetails(error, serializableData);
1062
1100
  const code = getPlaybackErrorCodeText(error);
1063
1101
  setNextPlaying(false);
1064
- setErrorState({ message, error, data, details });
1102
+ setErrorState({ message, error, data: serializableData, details });
1065
1103
  console.error("[VideoPlayer] playback error", {
1066
1104
  message,
1067
1105
  code,
1068
1106
  details,
1069
1107
  error,
1070
- data
1108
+ data: serializableData
1071
1109
  });
1072
- (_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 });
1073
1111
  },
1074
1112
  [messages.defaultError, setNextPlaying]
1075
1113
  );
@@ -1188,6 +1226,7 @@ var VideoPlayerBase = (props, ref) => {
1188
1226
  block: "center",
1189
1227
  inline: "nearest"
1190
1228
  });
1229
+ afterScroll && afterScroll();
1191
1230
  }
1192
1231
  }
1193
1232
  }, [
@@ -1295,11 +1334,40 @@ var VideoPlayerBase = (props, ref) => {
1295
1334
  if (!video) return;
1296
1335
  const h = new HlsCtor(resolvedHlsConfig());
1297
1336
  hlsRef.current = h;
1337
+ let initSegmentUrl = null;
1298
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
+ });
1299
1342
  h.on(HlsCtor.Events.ERROR, (_evt, data) => {
1300
1343
  var _a2, _b2;
1301
1344
  if (isStaleLoad()) return;
1302
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
+ }
1303
1371
  if (onAudioError(data)) return;
1304
1372
  if (!fatal && (details === HlsCtor.ErrorDetails.BUFFER_APPEND_ERROR || details === "bufferAppendingError")) return;
1305
1373
  if (!fatal) {
@@ -1373,7 +1441,7 @@ var VideoPlayerBase = (props, ref) => {
1373
1441
  }
1374
1442
  reportError(
1375
1443
  details,
1376
- data,
1444
+ lastBufferAddCodecFailure.current ? { ...data, bufferAddCodecError: lastBufferAddCodecFailure.current, src: videoSrc, hlsVersion: HlsCtor.version } : data,
1377
1445
  errorType === HlsCtor.ErrorTypes.MEDIA_ERROR ? messages.streamDecodeFailed : messages.streamLoadFailed
1378
1446
  );
1379
1447
  return;
@@ -1614,6 +1682,7 @@ var VideoPlayerBase = (props, ref) => {
1614
1682
  const loadId = sourceLoadId.current + 1;
1615
1683
  sourceLoadId.current = loadId;
1616
1684
  clearErrorState();
1685
+ lastBufferAddCodecFailure.current = null;
1617
1686
  fatalReloadCount.current = 0;
1618
1687
  netRetryCount.current = 0;
1619
1688
  mediaRecoverCount.current = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikelroot/video-player",
3
- "version": "0.3.3",
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": "00fca415c7ef041917872f1349ff3739b1b8da47"
51
+ "gitHead": "3bc5c054756e591f2ba73678de16dd1dfc0bb80f"
52
52
  }