stormcloud-video-player 0.1.13 → 0.2.1

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/lib/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/ui/StormcloudVideoPlayer.tsx
2
+ import React, { useEffect, useRef, useMemo } from "react";
3
+
1
4
  // src/player/StormcloudVideoPlayer.ts
2
5
  import Hls from "hls.js";
3
6
 
@@ -1092,7 +1095,6 @@ var StormcloudVideoPlayer = class {
1092
1095
  }
1093
1096
  parseScte35Binary(data) {
1094
1097
  class BitReader {
1095
- // 0..7
1096
1098
  constructor(buf) {
1097
1099
  this.buf = buf;
1098
1100
  this.bytePos = 0;
@@ -1631,7 +1633,6 @@ var StormcloudVideoPlayer = class {
1631
1633
  };
1632
1634
 
1633
1635
  // src/ui/StormcloudVideoPlayer.tsx
1634
- import React, { useEffect, useRef, useMemo } from "react";
1635
1636
  import {
1636
1637
  FaPlay,
1637
1638
  FaPause,
@@ -1784,7 +1785,12 @@ var StormcloudVideoPlayerComponent = React.memo(
1784
1785
  const showNative = player.shouldShowNativeControls();
1785
1786
  setShouldShowNativeControls(showNative);
1786
1787
  onReady?.(player);
1787
- }).catch(() => {
1788
+ }).catch((error) => {
1789
+ console.error(
1790
+ "StormcloudVideoPlayer: Failed to load player:",
1791
+ error
1792
+ );
1793
+ onReady?.(player);
1788
1794
  });
1789
1795
  return () => {
1790
1796
  try {
@@ -2872,12 +2878,921 @@ var StormcloudVideoPlayerComponent = React.memo(
2872
2878
  return true;
2873
2879
  }
2874
2880
  );
2881
+
2882
+ // src/StormcloudPlayer.tsx
2883
+ import React3, { Component as Component4, Suspense } from "react";
2884
+
2885
+ // src/props.ts
2886
+ var noop = () => {
2887
+ };
2888
+ var defaultProps = {
2889
+ playing: false,
2890
+ loop: false,
2891
+ controls: true,
2892
+ volume: 1,
2893
+ muted: false,
2894
+ playbackRate: 1,
2895
+ width: "100%",
2896
+ height: "auto",
2897
+ style: {},
2898
+ progressInterval: 1e3,
2899
+ playsInline: false,
2900
+ autoplay: false,
2901
+ preload: "metadata",
2902
+ poster: "",
2903
+ className: "",
2904
+ wrapperClassName: "",
2905
+ wrapperStyle: {},
2906
+ allowNativeHls: false,
2907
+ lowLatencyMode: false,
2908
+ driftToleranceMs: 1e3,
2909
+ immediateManifestAds: true,
2910
+ debugAdTiming: false,
2911
+ showCustomControls: false,
2912
+ licenseKey: "",
2913
+ adFailsafeTimeoutMs: 1e4,
2914
+ onStart: noop,
2915
+ onPlay: noop,
2916
+ onPause: noop,
2917
+ onBuffer: noop,
2918
+ onBufferEnd: noop,
2919
+ onEnded: noop,
2920
+ onError: noop,
2921
+ onDuration: noop,
2922
+ onSeek: noop,
2923
+ onProgress: noop,
2924
+ onVolumeToggle: noop,
2925
+ onFullscreenToggle: noop,
2926
+ onControlClick: noop
2927
+ };
2928
+
2929
+ // src/utils.ts
2930
+ import { lazy as reactLazy } from "react";
2931
+ var lazy = reactLazy;
2932
+ var omit = (object, keys) => {
2933
+ const result = { ...object };
2934
+ keys.forEach((key) => {
2935
+ delete result[key];
2936
+ });
2937
+ return result;
2938
+ };
2939
+ var isMediaStream = (url) => {
2940
+ return typeof window !== "undefined" && window.MediaStream && url instanceof window.MediaStream;
2941
+ };
2942
+ var supportsWebKitPresentationMode = () => {
2943
+ if (typeof window === "undefined") return false;
2944
+ const video = document.createElement("video");
2945
+ return "webkitSupportsPresentationMode" in video;
2946
+ };
2947
+ var randomString = () => {
2948
+ return Math.random().toString(36).substr(2, 9);
2949
+ };
2950
+ var parseQuery = (url) => {
2951
+ const query = {};
2952
+ const params = new URLSearchParams(url.split("?")[1] || "");
2953
+ params.forEach((value, key) => {
2954
+ query[key] = value;
2955
+ });
2956
+ return query;
2957
+ };
2958
+ var merge = (target, ...sources) => {
2959
+ if (!sources.length) return target;
2960
+ const source = sources.shift();
2961
+ if (isObject(target) && isObject(source)) {
2962
+ for (const key in source) {
2963
+ if (isObject(source[key])) {
2964
+ if (!target[key]) Object.assign(target, { [key]: {} });
2965
+ merge(target[key], source[key]);
2966
+ } else {
2967
+ Object.assign(target, { [key]: source[key] });
2968
+ }
2969
+ }
2970
+ }
2971
+ return merge(target, ...sources);
2972
+ };
2973
+ var isObject = (item) => {
2974
+ return item && typeof item === "object" && !Array.isArray(item);
2975
+ };
2976
+ var IS_BROWSER = typeof window !== "undefined" && window.document;
2977
+ var IS_GLOBAL = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
2978
+ var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(navigator.userAgent);
2979
+ var IS_SAFARI = IS_BROWSER && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
2980
+ var SUPPORTS_HLS = () => {
2981
+ if (!IS_BROWSER) return false;
2982
+ const video = document.createElement("video");
2983
+ return Boolean(video.canPlayType("application/vnd.apple.mpegurl"));
2984
+ };
2985
+ var SUPPORTS_DASH = () => {
2986
+ if (!IS_BROWSER) return false;
2987
+ const video = document.createElement("video");
2988
+ return Boolean(video.canPlayType("application/dash+xml"));
2989
+ };
2990
+
2991
+ // src/patterns.ts
2992
+ var HLS_EXTENSIONS = /\.(m3u8)($|\?)/i;
2993
+ var HLS_PATHS = /\/hls\//i;
2994
+ var DASH_EXTENSIONS = /\.(mpd)($|\?)/i;
2995
+ var VIDEO_EXTENSIONS = /\.(mp4|webm|ogg|avi|mov|wmv|flv|mkv)($|\?)/i;
2996
+ var AUDIO_EXTENSIONS = /\.(mp3|wav|ogg|aac|wma|flac|m4a)($|\?)/i;
2997
+ var canPlay = {
2998
+ hls: (url) => {
2999
+ if (!url || typeof url !== "string") return false;
3000
+ return HLS_EXTENSIONS.test(url) || HLS_PATHS.test(url);
3001
+ },
3002
+ dash: (url) => {
3003
+ if (!url || typeof url !== "string") return false;
3004
+ return DASH_EXTENSIONS.test(url);
3005
+ },
3006
+ video: (url) => {
3007
+ if (!url || typeof url !== "string") return false;
3008
+ return VIDEO_EXTENSIONS.test(url);
3009
+ },
3010
+ audio: (url) => {
3011
+ if (!url || typeof url !== "string") return false;
3012
+ return AUDIO_EXTENSIONS.test(url);
3013
+ },
3014
+ file: (url) => {
3015
+ if (!url || typeof url !== "string") return false;
3016
+ return VIDEO_EXTENSIONS.test(url) || AUDIO_EXTENSIONS.test(url);
3017
+ }
3018
+ };
3019
+
3020
+ // src/players/HlsPlayer.tsx
3021
+ import { Component } from "react";
3022
+ var HlsPlayer = class extends Component {
3023
+ constructor() {
3024
+ super(...arguments);
3025
+ this.player = null;
3026
+ this.mounted = false;
3027
+ this.load = async () => {
3028
+ if (!this.props.videoElement || !this.props.src) return;
3029
+ try {
3030
+ if (this.player) {
3031
+ this.player.destroy();
3032
+ this.player = null;
3033
+ }
3034
+ const config = {
3035
+ src: this.props.src,
3036
+ videoElement: this.props.videoElement
3037
+ };
3038
+ if (this.props.autoplay !== void 0)
3039
+ config.autoplay = this.props.autoplay;
3040
+ if (this.props.muted !== void 0) config.muted = this.props.muted;
3041
+ if (this.props.lowLatencyMode !== void 0)
3042
+ config.lowLatencyMode = this.props.lowLatencyMode;
3043
+ if (this.props.allowNativeHls !== void 0)
3044
+ config.allowNativeHls = this.props.allowNativeHls;
3045
+ if (this.props.driftToleranceMs !== void 0)
3046
+ config.driftToleranceMs = this.props.driftToleranceMs;
3047
+ if (this.props.immediateManifestAds !== void 0)
3048
+ config.immediateManifestAds = this.props.immediateManifestAds;
3049
+ if (this.props.debugAdTiming !== void 0)
3050
+ config.debugAdTiming = this.props.debugAdTiming;
3051
+ if (this.props.showCustomControls !== void 0)
3052
+ config.showCustomControls = this.props.showCustomControls;
3053
+ if (this.props.onVolumeToggle !== void 0)
3054
+ config.onVolumeToggle = this.props.onVolumeToggle;
3055
+ if (this.props.onFullscreenToggle !== void 0)
3056
+ config.onFullscreenToggle = this.props.onFullscreenToggle;
3057
+ if (this.props.onControlClick !== void 0)
3058
+ config.onControlClick = this.props.onControlClick;
3059
+ if (this.props.licenseKey !== void 0)
3060
+ config.licenseKey = this.props.licenseKey;
3061
+ if (this.props.adFailsafeTimeoutMs !== void 0)
3062
+ config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3063
+ this.player = new StormcloudVideoPlayer(config);
3064
+ this.props.onMount?.(this);
3065
+ await this.player.load();
3066
+ if (this.mounted) {
3067
+ this.props.onReady?.();
3068
+ }
3069
+ } catch (error) {
3070
+ if (this.mounted) {
3071
+ this.props.onError?.(error);
3072
+ }
3073
+ }
3074
+ };
3075
+ this.play = () => {
3076
+ if (this.props.videoElement) {
3077
+ this.props.videoElement.play();
3078
+ this.props.onPlay?.();
3079
+ }
3080
+ };
3081
+ this.pause = () => {
3082
+ if (this.props.videoElement) {
3083
+ this.props.videoElement.pause();
3084
+ this.props.onPause?.();
3085
+ }
3086
+ };
3087
+ this.stop = () => {
3088
+ this.pause();
3089
+ if (this.props.videoElement) {
3090
+ this.props.videoElement.currentTime = 0;
3091
+ }
3092
+ };
3093
+ this.seekTo = (seconds, keepPlaying) => {
3094
+ if (this.props.videoElement) {
3095
+ this.props.videoElement.currentTime = seconds;
3096
+ if (!keepPlaying) {
3097
+ this.pause();
3098
+ }
3099
+ }
3100
+ };
3101
+ this.setVolume = (volume) => {
3102
+ if (this.props.videoElement) {
3103
+ this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
3104
+ }
3105
+ };
3106
+ this.mute = () => {
3107
+ if (this.props.videoElement) {
3108
+ this.props.videoElement.muted = true;
3109
+ }
3110
+ };
3111
+ this.unmute = () => {
3112
+ if (this.props.videoElement) {
3113
+ this.props.videoElement.muted = false;
3114
+ }
3115
+ };
3116
+ this.setPlaybackRate = (rate) => {
3117
+ if (this.props.videoElement && rate > 0) {
3118
+ this.props.videoElement.playbackRate = rate;
3119
+ }
3120
+ };
3121
+ this.getDuration = () => {
3122
+ if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
3123
+ return this.props.videoElement.duration;
3124
+ }
3125
+ return null;
3126
+ };
3127
+ this.getCurrentTime = () => {
3128
+ if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
3129
+ return this.props.videoElement.currentTime;
3130
+ }
3131
+ return null;
3132
+ };
3133
+ this.getSecondsLoaded = () => {
3134
+ if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
3135
+ return this.props.videoElement.buffered.end(
3136
+ this.props.videoElement.buffered.length - 1
3137
+ );
3138
+ }
3139
+ return null;
3140
+ };
3141
+ this.getInternalPlayer = (key = "player") => {
3142
+ if (key === "player") return this.player;
3143
+ if (key === "video") return this.props.videoElement;
3144
+ if (key === "hls" && this.player) return this.player.hls;
3145
+ return null;
3146
+ };
3147
+ }
3148
+ componentDidMount() {
3149
+ this.mounted = true;
3150
+ this.load();
3151
+ }
3152
+ componentWillUnmount() {
3153
+ this.mounted = false;
3154
+ if (this.player) {
3155
+ this.player.destroy();
3156
+ this.player = null;
3157
+ }
3158
+ }
3159
+ componentDidUpdate(prevProps) {
3160
+ if (prevProps.src !== this.props.src) {
3161
+ this.load();
3162
+ }
3163
+ }
3164
+ render() {
3165
+ return null;
3166
+ }
3167
+ };
3168
+ HlsPlayer.displayName = "HlsPlayer";
3169
+ HlsPlayer.canPlay = canPlay.hls;
3170
+
3171
+ // src/players/FilePlayer.tsx
3172
+ import { Component as Component2 } from "react";
3173
+ var FilePlayer = class extends Component2 {
3174
+ constructor() {
3175
+ super(...arguments);
3176
+ this.mounted = false;
3177
+ this.ready = false;
3178
+ this.load = () => {
3179
+ if (!this.props.videoElement || !this.props.src) return;
3180
+ const video = this.props.videoElement;
3181
+ const handleLoadedMetadata = () => {
3182
+ if (this.mounted && !this.ready) {
3183
+ this.ready = true;
3184
+ this.props.onReady?.();
3185
+ }
3186
+ };
3187
+ const handlePlay = () => {
3188
+ if (this.mounted) {
3189
+ this.props.onPlay?.();
3190
+ }
3191
+ };
3192
+ const handlePause = () => {
3193
+ if (this.mounted) {
3194
+ this.props.onPause?.();
3195
+ }
3196
+ };
3197
+ const handleEnded = () => {
3198
+ if (this.mounted) {
3199
+ this.props.onEnded?.();
3200
+ }
3201
+ };
3202
+ const handleError = (error) => {
3203
+ if (this.mounted) {
3204
+ this.props.onError?.(error);
3205
+ }
3206
+ };
3207
+ const handleLoadedData = () => {
3208
+ if (this.mounted) {
3209
+ this.props.onLoaded?.();
3210
+ }
3211
+ };
3212
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
3213
+ video.addEventListener("play", handlePlay);
3214
+ video.addEventListener("pause", handlePause);
3215
+ video.addEventListener("ended", handleEnded);
3216
+ video.addEventListener("error", handleError);
3217
+ video.addEventListener("loadeddata", handleLoadedData);
3218
+ video.src = this.props.src;
3219
+ if (this.props.autoplay !== void 0) video.autoplay = this.props.autoplay;
3220
+ if (this.props.muted !== void 0) video.muted = this.props.muted;
3221
+ if (this.props.loop !== void 0) video.loop = this.props.loop;
3222
+ if (this.props.controls !== void 0) video.controls = this.props.controls;
3223
+ if (this.props.playsInline !== void 0)
3224
+ video.playsInline = this.props.playsInline;
3225
+ if (this.props.preload !== void 0)
3226
+ video.preload = this.props.preload;
3227
+ if (this.props.poster !== void 0) video.poster = this.props.poster;
3228
+ this.props.onMount?.(this);
3229
+ return () => {
3230
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
3231
+ video.removeEventListener("play", handlePlay);
3232
+ video.removeEventListener("pause", handlePause);
3233
+ video.removeEventListener("ended", handleEnded);
3234
+ video.removeEventListener("error", handleError);
3235
+ video.removeEventListener("loadeddata", handleLoadedData);
3236
+ };
3237
+ };
3238
+ this.play = () => {
3239
+ if (this.props.videoElement) {
3240
+ this.props.videoElement.play();
3241
+ }
3242
+ };
3243
+ this.pause = () => {
3244
+ if (this.props.videoElement) {
3245
+ this.props.videoElement.pause();
3246
+ }
3247
+ };
3248
+ this.stop = () => {
3249
+ this.pause();
3250
+ if (this.props.videoElement) {
3251
+ this.props.videoElement.currentTime = 0;
3252
+ }
3253
+ };
3254
+ this.seekTo = (seconds, keepPlaying) => {
3255
+ if (this.props.videoElement) {
3256
+ this.props.videoElement.currentTime = seconds;
3257
+ if (!keepPlaying) {
3258
+ this.pause();
3259
+ }
3260
+ }
3261
+ };
3262
+ this.setVolume = (volume) => {
3263
+ if (this.props.videoElement) {
3264
+ this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
3265
+ }
3266
+ };
3267
+ this.mute = () => {
3268
+ if (this.props.videoElement) {
3269
+ this.props.videoElement.muted = true;
3270
+ }
3271
+ };
3272
+ this.unmute = () => {
3273
+ if (this.props.videoElement) {
3274
+ this.props.videoElement.muted = false;
3275
+ }
3276
+ };
3277
+ this.setPlaybackRate = (rate) => {
3278
+ if (this.props.videoElement && rate > 0) {
3279
+ this.props.videoElement.playbackRate = rate;
3280
+ }
3281
+ };
3282
+ this.setLoop = (loop) => {
3283
+ if (this.props.videoElement) {
3284
+ this.props.videoElement.loop = loop;
3285
+ }
3286
+ };
3287
+ this.getDuration = () => {
3288
+ if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
3289
+ return this.props.videoElement.duration;
3290
+ }
3291
+ return null;
3292
+ };
3293
+ this.getCurrentTime = () => {
3294
+ if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
3295
+ return this.props.videoElement.currentTime;
3296
+ }
3297
+ return null;
3298
+ };
3299
+ this.getSecondsLoaded = () => {
3300
+ if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
3301
+ return this.props.videoElement.buffered.end(
3302
+ this.props.videoElement.buffered.length - 1
3303
+ );
3304
+ }
3305
+ return null;
3306
+ };
3307
+ this.getInternalPlayer = (key = "player") => {
3308
+ if (key === "video") return this.props.videoElement;
3309
+ return null;
3310
+ };
3311
+ this.enablePIP = async () => {
3312
+ if (this.props.videoElement && "requestPictureInPicture" in this.props.videoElement) {
3313
+ try {
3314
+ await this.props.videoElement.requestPictureInPicture();
3315
+ } catch (error) {
3316
+ console.warn("Picture-in-Picture failed:", error);
3317
+ }
3318
+ }
3319
+ };
3320
+ this.disablePIP = async () => {
3321
+ if (document.pictureInPictureElement) {
3322
+ try {
3323
+ await document.exitPictureInPicture();
3324
+ } catch (error) {
3325
+ console.warn("Exit Picture-in-Picture failed:", error);
3326
+ }
3327
+ }
3328
+ };
3329
+ }
3330
+ componentDidMount() {
3331
+ this.mounted = true;
3332
+ this.load();
3333
+ }
3334
+ componentWillUnmount() {
3335
+ this.mounted = false;
3336
+ }
3337
+ componentDidUpdate(prevProps) {
3338
+ if (prevProps.src !== this.props.src) {
3339
+ this.load();
3340
+ }
3341
+ }
3342
+ render() {
3343
+ return null;
3344
+ }
3345
+ };
3346
+ FilePlayer.displayName = "FilePlayer";
3347
+ FilePlayer.canPlay = canPlay.file;
3348
+
3349
+ // src/players/index.ts
3350
+ var players = [
3351
+ {
3352
+ key: "hls",
3353
+ name: "HLS Player",
3354
+ canPlay: canPlay.hls,
3355
+ lazyPlayer: lazy(() => Promise.resolve({ default: HlsPlayer }))
3356
+ },
3357
+ {
3358
+ key: "file",
3359
+ name: "File Player",
3360
+ canPlay: canPlay.file,
3361
+ canEnablePIP: (url) => {
3362
+ return canPlay.file(url) && (document.pictureInPictureEnabled || typeof document.webkitSupportsPresentationMode === "function");
3363
+ },
3364
+ lazyPlayer: lazy(() => Promise.resolve({ default: FilePlayer }))
3365
+ }
3366
+ ];
3367
+ var players_default = players;
3368
+
3369
+ // src/Player.tsx
3370
+ import React2, { Component as Component3 } from "react";
3371
+ var SEEK_ON_PLAY_EXPIRY = 5e3;
3372
+ var Player = class extends Component3 {
3373
+ constructor() {
3374
+ super(...arguments);
3375
+ this.mounted = false;
3376
+ this.isReady = false;
3377
+ this.isPlaying = false;
3378
+ this.isLoading = true;
3379
+ this.loadOnReady = null;
3380
+ this.startOnPlay = true;
3381
+ this.seekOnPlay = null;
3382
+ this.onDurationCalled = false;
3383
+ this.handlePlayerMount = (player) => {
3384
+ if (this.player) {
3385
+ this.progress();
3386
+ return;
3387
+ }
3388
+ this.player = player;
3389
+ this.player.load(this.props.src);
3390
+ this.progress();
3391
+ };
3392
+ this.getInternalPlayer = (key) => {
3393
+ if (!this.player) return null;
3394
+ return this.player.getInternalPlayer(key);
3395
+ };
3396
+ this.progress = () => {
3397
+ if (this.props.src && this.player && this.isReady) {
3398
+ const playedSeconds = this.getCurrentTime() || 0;
3399
+ const loadedSeconds = this.getSecondsLoaded();
3400
+ const duration = this.getDuration();
3401
+ if (duration) {
3402
+ const progress = {
3403
+ playedSeconds,
3404
+ played: playedSeconds / duration,
3405
+ loaded: 0,
3406
+ loadedSeconds: 0
3407
+ };
3408
+ if (loadedSeconds !== null) {
3409
+ progress.loadedSeconds = loadedSeconds;
3410
+ progress.loaded = loadedSeconds / duration;
3411
+ }
3412
+ if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {
3413
+ this.props.onProgress?.(progress);
3414
+ }
3415
+ this.prevPlayed = progress.playedSeconds;
3416
+ this.prevLoaded = progress.loadedSeconds;
3417
+ }
3418
+ }
3419
+ this.progressTimeout = window.setTimeout(
3420
+ this.progress,
3421
+ this.props.progressInterval || 1e3
3422
+ );
3423
+ };
3424
+ this.handleReady = () => {
3425
+ if (!this.mounted) return;
3426
+ this.isReady = true;
3427
+ this.isLoading = false;
3428
+ const { onReady, playing, volume, muted } = this.props;
3429
+ onReady();
3430
+ if (!muted && volume !== null) {
3431
+ this.player.setVolume(volume);
3432
+ }
3433
+ if (this.loadOnReady) {
3434
+ this.player.load(this.loadOnReady, true);
3435
+ this.loadOnReady = null;
3436
+ } else if (playing) {
3437
+ this.player.play();
3438
+ }
3439
+ this.handleDurationCheck();
3440
+ };
3441
+ this.handlePlay = () => {
3442
+ this.isPlaying = true;
3443
+ this.isLoading = false;
3444
+ const { onStart, onPlay, playbackRate } = this.props;
3445
+ if (this.startOnPlay) {
3446
+ if (this.player.setPlaybackRate && playbackRate !== 1) {
3447
+ this.player.setPlaybackRate(playbackRate);
3448
+ }
3449
+ onStart?.();
3450
+ this.startOnPlay = false;
3451
+ }
3452
+ onPlay?.();
3453
+ if (this.seekOnPlay) {
3454
+ this.seekTo(this.seekOnPlay);
3455
+ this.seekOnPlay = null;
3456
+ }
3457
+ this.handleDurationCheck();
3458
+ };
3459
+ this.handlePause = (e) => {
3460
+ this.isPlaying = false;
3461
+ if (!this.isLoading) {
3462
+ this.props.onPause?.(e);
3463
+ }
3464
+ };
3465
+ this.handleEnded = () => {
3466
+ const { activePlayer, loop, onEnded } = this.props;
3467
+ if (activePlayer.loopOnEnded && loop) {
3468
+ this.seekTo(0);
3469
+ }
3470
+ if (!loop) {
3471
+ this.isPlaying = false;
3472
+ onEnded?.();
3473
+ }
3474
+ };
3475
+ this.handleError = (...args) => {
3476
+ this.isLoading = false;
3477
+ this.props.onError?.(args[0], args[1], args[2], args[3]);
3478
+ };
3479
+ this.handleDurationCheck = () => {
3480
+ clearTimeout(this.durationCheckTimeout);
3481
+ const duration = this.getDuration();
3482
+ if (duration) {
3483
+ if (!this.onDurationCalled) {
3484
+ this.props.onDuration?.(duration);
3485
+ this.onDurationCalled = true;
3486
+ }
3487
+ } else {
3488
+ this.durationCheckTimeout = window.setTimeout(
3489
+ this.handleDurationCheck,
3490
+ 100
3491
+ );
3492
+ }
3493
+ };
3494
+ this.handleLoaded = () => {
3495
+ this.isLoading = false;
3496
+ };
3497
+ }
3498
+ componentDidMount() {
3499
+ this.mounted = true;
3500
+ }
3501
+ componentWillUnmount() {
3502
+ clearTimeout(this.progressTimeout);
3503
+ clearTimeout(this.durationCheckTimeout);
3504
+ this.mounted = false;
3505
+ }
3506
+ componentDidUpdate(prevProps) {
3507
+ if (!this.player) return;
3508
+ const { src, playing, volume, muted, playbackRate, loop, activePlayer } = this.props;
3509
+ if (prevProps.src !== src) {
3510
+ if (this.isLoading && !activePlayer.forceLoad && !isMediaStream(src)) {
3511
+ console.warn(
3512
+ `StormcloudPlayer: the attempt to load ${src} is being deferred until the player has loaded`
3513
+ );
3514
+ this.loadOnReady = src || null;
3515
+ return;
3516
+ }
3517
+ this.isLoading = true;
3518
+ this.startOnPlay = true;
3519
+ this.onDurationCalled = false;
3520
+ this.player.load(src, this.isReady);
3521
+ }
3522
+ if (!prevProps.playing && playing && !this.isPlaying) {
3523
+ this.player.play();
3524
+ }
3525
+ if (prevProps.playing && !playing && this.isPlaying) {
3526
+ this.player.pause();
3527
+ }
3528
+ if (prevProps.volume !== volume && volume !== null) {
3529
+ this.player.setVolume(volume);
3530
+ }
3531
+ if (prevProps.muted !== muted) {
3532
+ if (muted) {
3533
+ this.player.mute();
3534
+ } else {
3535
+ this.player.unmute();
3536
+ if (volume !== null) {
3537
+ setTimeout(() => this.player.setVolume(volume));
3538
+ }
3539
+ }
3540
+ }
3541
+ if (prevProps.playbackRate !== playbackRate && this.player.setPlaybackRate) {
3542
+ this.player.setPlaybackRate(playbackRate);
3543
+ }
3544
+ if (prevProps.loop !== loop && this.player.setLoop) {
3545
+ this.player.setLoop(loop);
3546
+ }
3547
+ }
3548
+ getDuration() {
3549
+ if (!this.isReady) return null;
3550
+ return this.player.getDuration();
3551
+ }
3552
+ getCurrentTime() {
3553
+ if (!this.isReady) return null;
3554
+ return this.player.getCurrentTime();
3555
+ }
3556
+ getSecondsLoaded() {
3557
+ if (!this.isReady) return null;
3558
+ return this.player.getSecondsLoaded();
3559
+ }
3560
+ seekTo(amount, type, keepPlaying) {
3561
+ if (!this.isReady) {
3562
+ if (amount !== 0) {
3563
+ this.seekOnPlay = amount;
3564
+ setTimeout(() => {
3565
+ this.seekOnPlay = null;
3566
+ }, SEEK_ON_PLAY_EXPIRY);
3567
+ }
3568
+ return;
3569
+ }
3570
+ const isFraction = !type ? amount > 0 && amount < 1 : type === "fraction";
3571
+ if (isFraction) {
3572
+ const duration = this.player.getDuration();
3573
+ if (!duration) {
3574
+ console.warn(
3575
+ "StormcloudPlayer: could not seek using fraction \u2013 duration not yet available"
3576
+ );
3577
+ return;
3578
+ }
3579
+ this.player.seekTo(duration * amount, keepPlaying);
3580
+ return;
3581
+ }
3582
+ this.player.seekTo(amount, keepPlaying);
3583
+ }
3584
+ render() {
3585
+ const Player2 = this.props.activePlayer;
3586
+ if (!Player2) {
3587
+ return null;
3588
+ }
3589
+ return React2.createElement(Player2, {
3590
+ ...this.props,
3591
+ onMount: this.handlePlayerMount,
3592
+ onReady: this.handleReady,
3593
+ onPlay: this.handlePlay,
3594
+ onPause: this.handlePause,
3595
+ onEnded: this.handleEnded,
3596
+ onLoaded: this.handleLoaded,
3597
+ onError: this.handleError
3598
+ });
3599
+ }
3600
+ };
3601
+ Player.displayName = "Player";
3602
+ Player.defaultProps = defaultProps;
3603
+
3604
+ // src/StormcloudPlayer.tsx
3605
+ var IS_BROWSER2 = typeof window !== "undefined" && window.document;
3606
+ var IS_GLOBAL2 = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
3607
+ var UniversalSuspense = IS_BROWSER2 || IS_GLOBAL2 ? Suspense : () => null;
3608
+ var SUPPORTED_PROPS = [
3609
+ "src",
3610
+ "playing",
3611
+ "loop",
3612
+ "controls",
3613
+ "volume",
3614
+ "muted",
3615
+ "playbackRate",
3616
+ "width",
3617
+ "height",
3618
+ "style",
3619
+ "progressInterval",
3620
+ "playsInline",
3621
+ "autoplay",
3622
+ "preload",
3623
+ "poster",
3624
+ "className",
3625
+ "wrapperClassName",
3626
+ "wrapperStyle",
3627
+ "allowNativeHls",
3628
+ "lowLatencyMode",
3629
+ "driftToleranceMs",
3630
+ "immediateManifestAds",
3631
+ "debugAdTiming",
3632
+ "showCustomControls",
3633
+ "licenseKey",
3634
+ "adFailsafeTimeoutMs",
3635
+ "onReady",
3636
+ "onStart",
3637
+ "onPlay",
3638
+ "onPause",
3639
+ "onBuffer",
3640
+ "onBufferEnd",
3641
+ "onEnded",
3642
+ "onError",
3643
+ "onDuration",
3644
+ "onSeek",
3645
+ "onProgress",
3646
+ "onVolumeToggle",
3647
+ "onFullscreenToggle",
3648
+ "onControlClick"
3649
+ ];
3650
+ var customPlayers = [];
3651
+ var createStormcloudPlayer = (playerList, fallback) => {
3652
+ var _a;
3653
+ return _a = class extends Component4 {
3654
+ constructor() {
3655
+ super(...arguments);
3656
+ this.state = {
3657
+ showPreview: false
3658
+ };
3659
+ this.references = {
3660
+ wrapper: (wrapper) => {
3661
+ this.wrapper = wrapper;
3662
+ },
3663
+ player: (player) => {
3664
+ this.player = player;
3665
+ }
3666
+ };
3667
+ this.getActivePlayer = (src) => {
3668
+ if (!src) return null;
3669
+ for (const player of [...customPlayers, ...playerList]) {
3670
+ if (player.canPlay(src)) {
3671
+ return player;
3672
+ }
3673
+ }
3674
+ if (fallback) {
3675
+ return fallback;
3676
+ }
3677
+ return null;
3678
+ };
3679
+ this.getAttributes = (src) => {
3680
+ return omit(this.props, SUPPORTED_PROPS);
3681
+ };
3682
+ this.handleReady = () => {
3683
+ this.props.onReady?.(this);
3684
+ };
3685
+ this.seekTo = (fraction, type, keepPlaying) => {
3686
+ if (!this.player) return null;
3687
+ this.player.seekTo(fraction, type, keepPlaying);
3688
+ };
3689
+ this.getCurrentTime = () => {
3690
+ if (!this.player) return null;
3691
+ return this.player.getCurrentTime();
3692
+ };
3693
+ this.getSecondsLoaded = () => {
3694
+ if (!this.player) return null;
3695
+ return this.player.getSecondsLoaded();
3696
+ };
3697
+ this.getDuration = () => {
3698
+ if (!this.player) return null;
3699
+ return this.player.getDuration();
3700
+ };
3701
+ this.getInternalPlayer = (key = "player") => {
3702
+ if (!this.player) return null;
3703
+ return this.player.getInternalPlayer(key);
3704
+ };
3705
+ this.renderActivePlayer = (src) => {
3706
+ if (!src) return null;
3707
+ const activePlayer = this.getActivePlayer(src);
3708
+ if (!activePlayer) return null;
3709
+ return React3.createElement(Player, {
3710
+ ...this.props,
3711
+ key: activePlayer.key,
3712
+ ref: this.references.player,
3713
+ activePlayer: activePlayer.lazyPlayer || activePlayer,
3714
+ onReady: this.handleReady
3715
+ });
3716
+ };
3717
+ }
3718
+ render() {
3719
+ const {
3720
+ src,
3721
+ style,
3722
+ width,
3723
+ height,
3724
+ fallback: fallbackElement,
3725
+ wrapper: Wrapper
3726
+ } = this.props;
3727
+ const attributes = this.getAttributes(src);
3728
+ const wrapperRef = typeof Wrapper === "string" ? this.references.wrapper : void 0;
3729
+ return React3.createElement(
3730
+ Wrapper,
3731
+ {
3732
+ ref: wrapperRef,
3733
+ style: { ...style, width, height },
3734
+ ...attributes
3735
+ },
3736
+ React3.createElement(
3737
+ UniversalSuspense,
3738
+ { fallback: fallbackElement },
3739
+ this.renderActivePlayer(src)
3740
+ )
3741
+ );
3742
+ }
3743
+ }, _a.displayName = "StormcloudPlayer", _a.defaultProps = {
3744
+ ...defaultProps,
3745
+ fallback: null,
3746
+ wrapper: "div"
3747
+ }, _a.addCustomPlayer = (player) => {
3748
+ customPlayers.push(player);
3749
+ }, _a.removeCustomPlayers = () => {
3750
+ customPlayers.length = 0;
3751
+ }, _a.canPlay = (src) => {
3752
+ for (const Player2 of [...customPlayers, ...playerList]) {
3753
+ if (Player2.canPlay(src)) {
3754
+ return true;
3755
+ }
3756
+ }
3757
+ return false;
3758
+ }, _a.canEnablePIP = (src) => {
3759
+ for (const Player2 of [...customPlayers, ...playerList]) {
3760
+ if (Player2.canEnablePIP && Player2.canEnablePIP(src)) {
3761
+ return true;
3762
+ }
3763
+ }
3764
+ return false;
3765
+ }, _a;
3766
+ };
3767
+ var StormcloudPlayer = createStormcloudPlayer(
3768
+ players_default,
3769
+ players_default[players_default.length - 1]
3770
+ );
3771
+ var StormcloudPlayer_default = StormcloudPlayer;
2875
3772
  export {
3773
+ IS_BROWSER,
3774
+ IS_GLOBAL,
3775
+ IS_IOS,
3776
+ IS_SAFARI,
3777
+ SUPPORTS_DASH,
3778
+ SUPPORTS_HLS,
3779
+ StormcloudPlayer_default as StormcloudPlayer,
2876
3780
  StormcloudVideoPlayer,
2877
3781
  StormcloudVideoPlayerComponent,
3782
+ canPlay,
3783
+ createStormcloudPlayer,
3784
+ StormcloudVideoPlayerComponent as default,
2878
3785
  getBrowserID,
2879
3786
  getClientInfo,
3787
+ isMediaStream,
3788
+ lazy,
3789
+ merge,
3790
+ omit,
3791
+ parseQuery,
3792
+ players_default as players,
3793
+ randomString,
2880
3794
  sendHeartbeat,
2881
- sendInitialTracking
3795
+ sendInitialTracking,
3796
+ supportsWebKitPresentationMode
2882
3797
  };
2883
3798
  //# sourceMappingURL=index.js.map