analytica-frontend-lib 1.1.90 → 1.1.91

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.
@@ -572,6 +572,7 @@ var VideoPlayer = ({
572
572
  const [showControls, setShowControls] = useState3(true);
573
573
  const [hasCompleted, setHasCompleted] = useState3(false);
574
574
  const [showCaptions, setShowCaptions] = useState3(false);
575
+ const [subtitlesValidation, setSubtitlesValidation] = useState3("idle");
575
576
  useEffect2(() => {
576
577
  setHasCompleted(false);
577
578
  }, [src]);
@@ -857,11 +858,12 @@ var VideoPlayer = ({
857
858
  setShowSpeedMenu(!showSpeedMenu);
858
859
  }, [showSpeedMenu]);
859
860
  const toggleCaptions = useCallback2(() => {
860
- if (!trackRef.current?.track || !subtitles) return;
861
+ if (!trackRef.current?.track || !subtitles || subtitlesValidation !== "valid")
862
+ return;
861
863
  const newShowCaptions = !showCaptions;
862
864
  setShowCaptions(newShowCaptions);
863
- trackRef.current.track.mode = newShowCaptions && subtitles ? "showing" : "hidden";
864
- }, [showCaptions, subtitles]);
865
+ trackRef.current.track.mode = newShowCaptions ? "showing" : "hidden";
866
+ }, [showCaptions, subtitles, subtitlesValidation]);
865
867
  const checkVideoCompletion = useCallback2(
866
868
  (progressPercent) => {
867
869
  if (progressPercent >= 95 && !hasCompleted) {
@@ -889,11 +891,58 @@ var VideoPlayer = ({
889
891
  setDuration(videoRef.current.duration);
890
892
  }
891
893
  }, []);
894
+ useEffect2(() => {
895
+ const controller = new AbortController();
896
+ const validateSubtitles = async () => {
897
+ if (!subtitles) {
898
+ setSubtitlesValidation("idle");
899
+ return;
900
+ }
901
+ setSubtitlesValidation("validating");
902
+ try {
903
+ if (subtitles.startsWith("data:")) {
904
+ setSubtitlesValidation("valid");
905
+ return;
906
+ }
907
+ const response = await fetch(subtitles, {
908
+ method: "HEAD",
909
+ signal: controller.signal
910
+ });
911
+ if (response.ok) {
912
+ const contentType = response.headers.get("content-type");
913
+ const isValidType = !contentType || contentType.includes("text/vtt") || contentType.includes("text/plain") || contentType.includes("application/octet-stream");
914
+ if (isValidType) {
915
+ setSubtitlesValidation("valid");
916
+ } else {
917
+ setSubtitlesValidation("invalid");
918
+ console.warn(
919
+ `Subtitles URL has invalid content type: ${contentType}`
920
+ );
921
+ }
922
+ } else {
923
+ setSubtitlesValidation("invalid");
924
+ console.warn(
925
+ `Subtitles URL returned status: ${response.status} ${response.statusText}`
926
+ );
927
+ }
928
+ } catch (error) {
929
+ if (error instanceof Error && error.name === "AbortError") {
930
+ return;
931
+ }
932
+ console.warn("Subtitles URL validation failed:", error);
933
+ setSubtitlesValidation("invalid");
934
+ }
935
+ };
936
+ validateSubtitles();
937
+ return () => {
938
+ controller.abort();
939
+ };
940
+ }, [subtitles]);
892
941
  useEffect2(() => {
893
942
  if (trackRef.current?.track) {
894
- trackRef.current.track.mode = showCaptions && subtitles ? "showing" : "hidden";
943
+ trackRef.current.track.mode = showCaptions && subtitles && subtitlesValidation === "valid" ? "showing" : "hidden";
895
944
  }
896
- }, [subtitles, showCaptions]);
945
+ }, [subtitles, showCaptions, subtitlesValidation]);
897
946
  useEffect2(() => {
898
947
  const handleVisibilityChange = () => {
899
948
  if (document.hidden && isPlaying && videoRef.current) {
@@ -947,61 +996,57 @@ var VideoPlayer = ({
947
996
  const getBottomControlsOpacity = useCallback2(() => {
948
997
  return showControls ? "opacity-100" : "opacity-0";
949
998
  }, [showControls]);
999
+ const seekBackward = useCallback2(() => {
1000
+ if (videoRef.current) {
1001
+ videoRef.current.currentTime -= 10;
1002
+ }
1003
+ }, []);
1004
+ const seekForward = useCallback2(() => {
1005
+ if (videoRef.current) {
1006
+ videoRef.current.currentTime += 10;
1007
+ }
1008
+ }, []);
1009
+ const increaseVolume = useCallback2(() => {
1010
+ handleVolumeChange(Math.min(100, volume * 100 + 10));
1011
+ }, [handleVolumeChange, volume]);
1012
+ const decreaseVolume = useCallback2(() => {
1013
+ handleVolumeChange(Math.max(0, volume * 100 - 10));
1014
+ }, [handleVolumeChange, volume]);
950
1015
  const handleVideoKeyDown = useCallback2(
951
1016
  (e) => {
952
- if (e.key) {
953
- e.stopPropagation();
954
- showControlsWithTimer();
955
- }
956
- switch (e.key) {
957
- case " ":
958
- case "Enter":
959
- e.preventDefault();
960
- togglePlayPause();
961
- break;
962
- case "ArrowLeft":
963
- e.preventDefault();
964
- if (videoRef.current) {
965
- videoRef.current.currentTime -= 10;
966
- }
967
- break;
968
- case "ArrowRight":
969
- e.preventDefault();
970
- if (videoRef.current) {
971
- videoRef.current.currentTime += 10;
972
- }
973
- break;
974
- case "ArrowUp":
975
- e.preventDefault();
976
- handleVolumeChange(Math.min(100, volume * 100 + 10));
977
- break;
978
- case "ArrowDown":
979
- e.preventDefault();
980
- handleVolumeChange(Math.max(0, volume * 100 - 10));
981
- break;
982
- case "m":
983
- case "M":
984
- e.preventDefault();
985
- toggleMute();
986
- break;
987
- case "f":
988
- case "F":
989
- e.preventDefault();
990
- toggleFullscreen();
991
- break;
992
- default:
993
- break;
1017
+ if (!e.key) return;
1018
+ e.stopPropagation();
1019
+ showControlsWithTimer();
1020
+ const keyHandlers = {
1021
+ " ": togglePlayPause,
1022
+ Enter: togglePlayPause,
1023
+ ArrowLeft: seekBackward,
1024
+ ArrowRight: seekForward,
1025
+ ArrowUp: increaseVolume,
1026
+ ArrowDown: decreaseVolume,
1027
+ m: toggleMute,
1028
+ M: toggleMute,
1029
+ f: toggleFullscreen,
1030
+ F: toggleFullscreen
1031
+ };
1032
+ const handler = keyHandlers[e.key];
1033
+ if (handler) {
1034
+ e.preventDefault();
1035
+ handler();
994
1036
  }
995
1037
  },
996
1038
  [
997
1039
  showControlsWithTimer,
998
1040
  togglePlayPause,
999
- handleVolumeChange,
1000
- volume,
1041
+ seekBackward,
1042
+ seekForward,
1043
+ increaseVolume,
1044
+ decreaseVolume,
1001
1045
  toggleMute,
1002
1046
  toggleFullscreen
1003
1047
  ]
1004
1048
  );
1049
+ const groupedSubTitleValid = subtitles && subtitlesValidation === "valid";
1005
1050
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
1006
1051
  (title || subtitleText) && /* @__PURE__ */ jsxs("div", { className: "bg-subject-1 px-8 py-4 flex items-end justify-between min-h-20", children: [
1007
1052
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
@@ -1075,9 +1120,9 @@ var VideoPlayer = ({
1075
1120
  {
1076
1121
  ref: trackRef,
1077
1122
  kind: "captions",
1078
- src: subtitles || "data:text/vtt;charset=utf-8,WEBVTT",
1123
+ src: groupedSubTitleValid ? subtitles : "data:text/vtt;charset=utf-8,WEBVTT",
1079
1124
  srcLang: "pt-br",
1080
- label: subtitles ? "Legendas em Portugu\xEAs" : "Sem legendas dispon\xEDveis",
1125
+ label: groupedSubTitleValid ? "Legendas em Portugu\xEAs" : "Sem legendas dispon\xEDveis",
1081
1126
  default: false
1082
1127
  }
1083
1128
  )
@@ -1166,7 +1211,7 @@ var VideoPlayer = ({
1166
1211
  showSlider: !isUltraSmallMobile
1167
1212
  }
1168
1213
  ),
1169
- subtitles && /* @__PURE__ */ jsx4(
1214
+ groupedSubTitleValid && /* @__PURE__ */ jsx4(
1170
1215
  IconButton_default,
1171
1216
  {
1172
1217
  icon: /* @__PURE__ */ jsx4(ClosedCaptioning, { size: getIconSize() }),