@eluvio/elv-player-js 1.0.140 → 2.0.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.
Files changed (102) hide show
  1. package/README.md +35 -6
  2. package/dist/.vite/manifest.json +67 -0
  3. package/dist/Analytics-HWXR7tWt.mjs +2028 -0
  4. package/dist/Analytics-IUVysdzU.js +29 -0
  5. package/dist/dash.all.min-1QS9Xbir.js +25 -0
  6. package/dist/dash.all.min-9V1xYBRv.mjs +19428 -0
  7. package/dist/elv-player-js.cjs.js +1 -0
  8. package/dist/elv-player-js.css +1 -0
  9. package/dist/elv-player-js.es.js +5 -0
  10. package/dist/hls-1eCRapWm.mjs +15461 -0
  11. package/dist/hls-6O5SV1FQ.js +26 -0
  12. package/dist/index-6cMQneJf.mjs +2273 -0
  13. package/dist/index-C8mwW09z.js +23 -0
  14. package/dist/index-J4QpmTkA.js +367 -0
  15. package/dist/index-hvQzQ6UX.mjs +67432 -0
  16. package/lib/index.js +7 -0
  17. package/{src → lib/player}/Analytics.js +9 -8
  18. package/lib/player/Controls.js +913 -0
  19. package/{src → lib/player}/FairPlay.js +2 -0
  20. package/lib/player/Player.js +881 -0
  21. package/lib/player/PlayerParameters.js +173 -0
  22. package/lib/static/icons/Icons.js +29 -0
  23. package/lib/static/icons/svgs/backward-circle.svg +5 -0
  24. package/lib/static/icons/svgs/backward.svg +4 -0
  25. package/lib/static/icons/svgs/captions-off.svg +7 -0
  26. package/lib/static/icons/svgs/captions.svg +6 -0
  27. package/lib/static/icons/svgs/check.svg +1 -0
  28. package/lib/static/icons/svgs/chevron-left.svg +1 -0
  29. package/lib/static/icons/svgs/chevron-right.svg +1 -0
  30. package/lib/static/icons/svgs/forward-circle.svg +5 -0
  31. package/lib/static/icons/svgs/forward.svg +4 -0
  32. package/{src/static/icons/media/Full Screen icon.svg → lib/static/icons/svgs/full-screen.svg} +1 -1
  33. package/lib/static/icons/svgs/large-play-circle.svg +4 -0
  34. package/lib/static/icons/svgs/list.svg +1 -0
  35. package/{src/static/icons → lib/static/icons/svgs}/minimize.svg +1 -1
  36. package/{src/static/icons/media/Pause icon.svg → lib/static/icons/svgs/pause-circle.svg} +3 -3
  37. package/lib/static/icons/svgs/pause.svg +1 -0
  38. package/{src/static/icons/media/Play icon.svg → lib/static/icons/svgs/play-circle.svg} +1 -1
  39. package/lib/static/icons/svgs/play.svg +1 -0
  40. package/lib/static/icons/svgs/rotate-cw.svg +1 -0
  41. package/lib/static/icons/svgs/settings.svg +11 -0
  42. package/{src/static/icons/media/skip back icon.svg → lib/static/icons/svgs/skip-backward.svg} +2 -3
  43. package/{src/static/icons/media/Skip forward icon.svg → lib/static/icons/svgs/skip-forward.svg} +2 -3
  44. package/{src/static/icons/media/Volume icon.svg → lib/static/icons/svgs/volume-high.svg} +3 -3
  45. package/lib/static/icons/svgs/volume-low.svg +10 -0
  46. package/{src/static/icons/media/low volume icon.svg → lib/static/icons/svgs/volume-medium.svg} +2 -2
  47. package/{src/static/icons/media/no volume icon.svg → lib/static/icons/svgs/volume-off.svg} +3 -3
  48. package/lib/static/stylesheets/common.module.scss +486 -0
  49. package/lib/static/stylesheets/controls-tv.module.scss +488 -0
  50. package/lib/static/stylesheets/controls-web.module.scss +422 -0
  51. package/lib/static/stylesheets/player-profile-form.module.scss +141 -0
  52. package/lib/static/stylesheets/player.module.scss +92 -0
  53. package/lib/static/stylesheets/reset.module.scss +79 -0
  54. package/lib/static/stylesheets/ticket-form.module.scss +123 -0
  55. package/lib/ui/BuildIcons.cjs +44 -0
  56. package/lib/ui/Common.js +210 -0
  57. package/lib/ui/Components.jsx +342 -0
  58. package/lib/ui/Observers.js +449 -0
  59. package/lib/ui/PlayerProfileForm.jsx +106 -0
  60. package/lib/ui/PlayerUI.jsx +317 -0
  61. package/lib/ui/TVControls.jsx +337 -0
  62. package/lib/ui/TicketForm.jsx +147 -0
  63. package/lib/ui/WebControls.jsx +290 -0
  64. package/package.json +35 -47
  65. package/dist/index.js +0 -2
  66. package/dist/index.js.LICENSE.txt +0 -80
  67. package/src/BuildIcons.js +0 -27
  68. package/src/PlayerControls.js +0 -1478
  69. package/src/index.js +0 -1417
  70. package/src/static/icons/Icons.js +0 -15
  71. package/src/static/icons/Settings icon.svg +0 -4
  72. package/src/static/icons/chat icon collapse.svg +0 -1
  73. package/src/static/icons/chat icon.svg +0 -11
  74. package/src/static/icons/chat send.svg +0 -1
  75. package/src/static/icons/full screen.svg +0 -1
  76. package/src/static/icons/media/LargePlayIcon.svg +0 -4
  77. package/src/static/icons/media/Settings icon.svg +0 -4
  78. package/src/static/icons/media/Skip backward icon.svg +0 -4
  79. package/src/static/icons/media/list.svg +0 -1
  80. package/src/static/icons/media/loop icon.svg +0 -12
  81. package/src/static/icons/media/shuffle icon.svg +0 -13
  82. package/src/static/icons/muted.svg +0 -11
  83. package/src/static/icons/pause.svg +0 -1
  84. package/src/static/icons/play circle.svg +0 -1
  85. package/src/static/icons/play.svg +0 -1
  86. package/src/static/icons/settings.svg +0 -1
  87. package/src/static/icons/slider circle.svg +0 -1
  88. package/src/static/icons/unmuted.svg +0 -10
  89. package/src/static/images/ELUV.IO logo embed player.png +0 -0
  90. package/src/static/images/ELUV.IO logo embed player.svg +0 -1
  91. package/src/static/images/ELUV.IO white 20 px V2.png +0 -0
  92. package/src/static/images/ELUVIO white.svg +0 -26
  93. package/src/static/images/Logo.png +0 -0
  94. package/src/static/stylesheets/player.scss +0 -1065
  95. package/webpack.config.js +0 -152
  96. /package/{src/static/icons → lib/static/icons/svgs}/arrow-left.svg +0 -0
  97. /package/{src/static/icons/live icon.svg → lib/static/icons/svgs/live.svg} +0 -0
  98. /package/{src/static/icons → lib/static/icons/svgs}/multiview.svg +0 -0
  99. /package/{src/static/icons/media → lib/static/icons/svgs}/next.svg +0 -0
  100. /package/{src/static/icons/media → lib/static/icons/svgs}/previous.svg +0 -0
  101. /package/{src/static/icons → lib/static/icons/svgs}/x.svg +0 -0
  102. /package/{dist/5897e28fa3e8ac0a2fae.png → lib/static/images/Logo.png} +0 -0
@@ -0,0 +1,342 @@
1
+ import CommonStyles from "../static/stylesheets/common.module.scss";
2
+
3
+ // eslint-disable-next-line no-unused-vars
4
+ import React, {createRef, useEffect, useState} from "react";
5
+ import {ACTIONS, SeekSliderKeyDown, VolumeSliderKeydown} from "./Common.js";
6
+ import {ObserveVideoBuffer, ObserveVideoTime, RegisterModal} from "./Observers.js";
7
+ import * as Icons from "../static/icons/Icons.js";
8
+ import {IconButton} from "./WebControls";
9
+
10
+ // Components
11
+
12
+ export const Spinner = ({light, className=""}) => (
13
+ <div className={`${className} ${CommonStyles["spinner"]} ${light ? CommonStyles["spinner--light"] : ""}`}>
14
+ <div className={CommonStyles["spinner-inner"]} />
15
+ </div>
16
+ );
17
+
18
+ export const SVG = ({icon, className=""}) => <div className={`${CommonStyles["svg"]} ${className}`} dangerouslySetInnerHTML={{__html: icon}} />;
19
+
20
+
21
+ const icons = {
22
+ [ACTIONS.PLAY]: Icons.PlayIcon,
23
+ [ACTIONS.PAUSE]: Icons.PauseIcon,
24
+ [ACTIONS.MUTE]: Icons.MutedIcon,
25
+ [ACTIONS.UNMUTE]: Icons.VolumeHighIcon,
26
+ [ACTIONS.VOLUME_DOWN]: Icons.VolumeLowIcon,
27
+ [ACTIONS.VOLUME_UP]: Icons.VolumeHighIcon,
28
+ [ACTIONS.SEEK_BACK]: Icons.BackwardIcon,
29
+ [ACTIONS.SEEK_FORWARD]: Icons.ForwardIcon,
30
+ [ACTIONS.PLAYBACK_RATE_DOWN]: Icons.BackwardIcon,
31
+ [ACTIONS.PLAYBACK_RATE_UP]: Icons.ForwardIcon,
32
+ [ACTIONS.SUBTITLES_ON]: Icons.CaptionsIcon,
33
+ [ACTIONS.SUBTITLES_OFF]: Icons.CaptionsOffIcon,
34
+ [ACTIONS.PLAY_PREVIOUS]: Icons.PreviousTrackIcon,
35
+ [ACTIONS.PLAY_NEXT]: Icons.NextTrackIcon
36
+ };
37
+
38
+ // Show a short indication when an action occurs due to keyboard controls etc.
39
+ export const UserActionIndicator = ({action}) => {
40
+ if(!action || !icons[action.action]) {
41
+ return;
42
+ }
43
+
44
+ return (
45
+ <div className={CommonStyles["user-action-indicator-container"]}>
46
+ <div className={CommonStyles["user-action-indicator"]}>
47
+ <SVG
48
+ icon={icons[action.action]}
49
+ aria-label={`Action indicator ${action}`}
50
+ className={CommonStyles["user-action-indicator-icon"]}
51
+ />
52
+ </div>
53
+ {
54
+ !action.text ? null :
55
+ <div className={CommonStyles["user-action-indicator-text"]}>
56
+ { action.text }
57
+ </div>
58
+ }
59
+ </div>
60
+ );
61
+ };
62
+
63
+ export const SeekBar = ({player, videoState, setRecentUserAction, className=""}) => {
64
+ const [currentTime, setCurrentTime] = useState(player.video.currentTime);
65
+ const [bufferFraction, setBufferFraction] = useState(0);
66
+ const [seekKeydownHandler, setSeekKeydownHandler] = useState(undefined);
67
+
68
+ useEffect(() => {
69
+ setSeekKeydownHandler(SeekSliderKeyDown(player, setRecentUserAction));
70
+
71
+ const disposeVideoTimeObserver = ObserveVideoTime({video: player.video, setCurrentTime, rate: 60});
72
+ const disposeVideoBufferObserver = ObserveVideoBuffer({video: player.video, setBufferFraction});
73
+
74
+ return () => {
75
+ disposeVideoTimeObserver && disposeVideoTimeObserver();
76
+ disposeVideoBufferObserver && disposeVideoBufferObserver();
77
+ };
78
+ }, []);
79
+
80
+ if(player.isLive) {
81
+ return null;
82
+ }
83
+
84
+ return (
85
+ <div className={`${className} ${CommonStyles["seek-container"]} ${className}`}>
86
+ <progress
87
+ max={1}
88
+ value={bufferFraction}
89
+ className={CommonStyles["seek-buffer"]}
90
+ />
91
+ <progress
92
+ max={1}
93
+ value={currentTime / videoState.duration || 0}
94
+ className={CommonStyles["seek-playhead"]}
95
+ />
96
+ <input
97
+ aria-label="Seek slider"
98
+ type="range"
99
+ min={0}
100
+ max={1}
101
+ step={0.00001}
102
+ value={currentTime / videoState.duration || 0}
103
+ onInput={event => player.controls.Seek({fraction: event.currentTarget.value})}
104
+ onKeyDown={seekKeydownHandler}
105
+ className={CommonStyles["seek-input"]}
106
+ />
107
+ </div>
108
+ );
109
+ };
110
+
111
+ export const VolumeControls = ({player, videoState}) => {
112
+ return (
113
+ <div className={CommonStyles["volume-controls"]}>
114
+ <IconButton
115
+ key="mute-button"
116
+ aria-label={videoState.muted ? "Unmute" : "Mute"}
117
+ icon={
118
+ videoState.muted || videoState.volume === 0 ? Icons.MutedIcon :
119
+ videoState.volume < 0.4 ? Icons.VolumeLowIcon :
120
+ videoState.volume < 0.8 ? Icons.VolumeMediumIcon :
121
+ Icons.VolumeHighIcon
122
+ }
123
+ onClick={() => player.controls.ToggleMuted()}
124
+ className={CommonStyles["volume-button"]}
125
+ />
126
+ <div className={CommonStyles["volume-slider"]}>
127
+ <progress
128
+ max={1}
129
+ value={videoState.muted ? 0 : videoState.volume}
130
+ className={CommonStyles["volume-progress"]}
131
+ />
132
+ <input
133
+ aria-label="Volume slider"
134
+ type="range"
135
+ min={0}
136
+ max={1}
137
+ step={0.001}
138
+ value={videoState.muted ? 0 : videoState.volume}
139
+ onInput={event => player.controls.SetVolume({fraction: event.currentTarget.value})}
140
+ onKeyDown={VolumeSliderKeydown(player)}
141
+ className={CommonStyles["volume-input"]}
142
+ />
143
+ </div>
144
+ </div>
145
+ );
146
+ };
147
+
148
+ export const SettingsMenu = ({player, Hide, className=""}) => {
149
+ const [activeMenu, setActiveMenu] = useState(undefined);
150
+ const [options, setOptions] = useState(undefined);
151
+ const menuRef = createRef();
152
+
153
+ useEffect(() => {
154
+ const UpdateSettings = () => setOptions(player.controls.GetOptions());
155
+
156
+ UpdateSettings();
157
+
158
+ const disposePlayerSettingsListener = player.controls.RegisterSettingsListener(UpdateSettings);
159
+
160
+ return () => disposePlayerSettingsListener && disposePlayerSettingsListener();
161
+ }, []);
162
+
163
+ useEffect(() => {
164
+ if(!menuRef || !menuRef.current) { return; }
165
+
166
+ const RemoveMenuListener = RegisterModal({element: menuRef.current.parentElement, Hide});
167
+
168
+ return () => {
169
+ RemoveMenuListener && RemoveMenuListener()
170
+ };
171
+ }, [menuRef]);
172
+
173
+ if(!options) { return null; }
174
+
175
+ // Delay firing of submenu change until after click outside handler has been called
176
+ const SetSubmenu = setting => setTimeout(() => setActiveMenu(setting));
177
+
178
+ const settings = {
179
+ quality: {
180
+ label: "Quality",
181
+ Update: index => player.controls.SetQualityLevel(index)
182
+ },
183
+ audio: {
184
+ label: "Audio",
185
+ Update: index => player.controls.SetAudioTrack(index)
186
+ },
187
+ text: {
188
+ label: "Subtitles",
189
+ Update: index => player.controls.SetTextTrack(index)
190
+ },
191
+ profile: {
192
+ label: "Player Profile",
193
+ Update: index => {
194
+ if(index === "custom") {
195
+ player.controls.ShowPlayerProfileForm();
196
+ Hide();
197
+ } else {
198
+ player.controls.SetPlayerProfile({profile: index});
199
+ }
200
+ }
201
+ },
202
+ rate: {
203
+ label: "Playback Rate",
204
+ Update: index => player.controls.SetPlaybackRate({index})
205
+ }
206
+ };
207
+
208
+ let content;
209
+ if(activeMenu) {
210
+ content = (
211
+ <div key="submenu" role="menu" className={`${CommonStyles["menu"]} ${CommonStyles["submenu"]} ${CommonStyles["settings-menu"]} ${className}`}>
212
+ <button
213
+ onClick={() => SetSubmenu(undefined)}
214
+ aria-label="Back to settings menu"
215
+ className={`${CommonStyles["menu-option"]} ${CommonStyles["menu-option-back"]}`}
216
+ >
217
+ <div dangerouslySetInnerHTML={{__html: Icons.LeftArrowIcon}} className={CommonStyles["menu-option-back-icon"]} />
218
+ <div>{ settings[activeMenu].label }</div>
219
+ </button>
220
+ {
221
+ options[activeMenu].options.map(option =>
222
+ <button
223
+ key={`option-${option.index}`}
224
+ role="menuitemradio"
225
+ aria-checked={option.active}
226
+ autoFocus={option.active}
227
+ aria-label={`${settings[activeMenu].label}: ${option.label || ""}`}
228
+ onClick={() => {
229
+ settings[activeMenu].Update(option.index);
230
+ SetSubmenu(undefined);
231
+ }}
232
+ className={`${CommonStyles["menu-option"]} ${option.active ? CommonStyles["menu-option-active"] : ""}`}
233
+ >
234
+ { option.label || "" }
235
+ { option.active ? <SVG icon={Icons.CheckmarkIcon} className={CommonStyles["menu-option-icon"]} /> : null }
236
+ </button>
237
+ )
238
+ }
239
+ </div>
240
+ );
241
+ } else {
242
+ content = (
243
+ <div key="menu" role="menu" className={`${CommonStyles["menu"]} ${CommonStyles["settings-menu"]} ${className}`}>
244
+ {
245
+ !options.hasQualityOptions <= 1 ? null :
246
+ <button autoFocus role="menuitem" onClick={() => SetSubmenu("quality")}
247
+ className={CommonStyles["menu-option"]}>
248
+ {`${settings.quality.label}: ${(options.quality.active && options.quality.active.activeLabel) || ""}`}
249
+ <SVG icon={Icons.ChevronRightIcon} className={CommonStyles["menu-option-icon"]}/>
250
+ </button>
251
+ }
252
+ {
253
+ !options.hasAudioOptions ? null :
254
+ <button autoFocus={!options.hasQualityOptions} role="menuitem" onClick={() => SetSubmenu("audio")} className={CommonStyles["menu-option"]}>
255
+ {`${settings.audio.label}: ${(options.audio.active && options.audio.active.label) || ""}`}
256
+ <SVG icon={Icons.ChevronRightIcon} className={CommonStyles["menu-option-icon"]}/>
257
+ </button>
258
+ }
259
+ {
260
+ !options.hasTextOptions ? null :
261
+ <button autoFocus={!options.hasQualityOptions && !options.hasAudioOptions} role="menuitem" onClick={() => SetSubmenu("text")} className={CommonStyles["menu-option"]}>
262
+ {`${settings.text.label}: ${(options.text.active && options.text.active.label) || ""}`}
263
+ <SVG icon={Icons.ChevronRightIcon} className={CommonStyles["menu-option-icon"]}/>
264
+ </button>
265
+ }
266
+ {
267
+ !options.hasProfileOptons ? null :
268
+ <button autoFocus={!options.hasQualityOptions && !options.hasAudioOptions && !options.hasTextOptions} role="menuitem" onClick={() => SetSubmenu("profile")} className={CommonStyles["menu-option"]}>
269
+ {`${settings.profile.label}: ${(options.profile.active && options.profile.active.label) || ""}`}
270
+ <SVG icon={Icons.ChevronRightIcon} className={CommonStyles["menu-option-icon"]}/>
271
+ </button>
272
+ }
273
+ {
274
+ !options.hasRateOptions ? null :
275
+ <button autoFocus={!options.hasQualityOptions && !options.hasAudioOptions && !options.hasTextOptions && !options.hasProfileOptons} role="menuitem" onClick={() => SetSubmenu("rate")} className={CommonStyles["menu-option"]}>
276
+ {`${settings.rate.label}: ${(options.rate.active && options.rate.active.label) || ""}`}
277
+ <SVG icon={Icons.ChevronRightIcon} className={CommonStyles["menu-option-icon"]}/>
278
+ </button>
279
+ }
280
+ </div>
281
+ );
282
+ }
283
+
284
+ return (
285
+ <div ref={menuRef} className={`${CommonStyles["menu-container"]}`}>
286
+ { content }
287
+ </div>
288
+ );
289
+ };
290
+
291
+ export const CollectionMenu = ({player, Hide, className=""}) => {
292
+ const menuRef = createRef();
293
+ const [collectionInfo, setCollectionInfo] = useState(undefined);
294
+
295
+ useEffect(() => {
296
+ const UpdateCollectionInfo = () => setCollectionInfo(player.controls.GetCollectionInfo());
297
+
298
+ UpdateCollectionInfo();
299
+
300
+ const disposePlayerSettingsListener = player.controls.RegisterSettingsListener(UpdateCollectionInfo);
301
+
302
+ return () => disposePlayerSettingsListener && disposePlayerSettingsListener();
303
+ }, []);
304
+
305
+ useEffect(() => {
306
+ if(!menuRef || !menuRef.current) { return; }
307
+
308
+ const RemoveMenuListener = RegisterModal({element: menuRef.current.parentElement, Hide});
309
+
310
+ return () => RemoveMenuListener && RemoveMenuListener();
311
+ }, [menuRef]);
312
+
313
+ if(!collectionInfo) { return null; }
314
+
315
+ const Select = mediaIndex => {
316
+ player.controls.CollectionPlay({mediaIndex});
317
+ Hide();
318
+ };
319
+
320
+ return (
321
+ <div key="menu" role="menu" className={`${CommonStyles["menu"]} ${CommonStyles["collection-menu"]} ${className}`} ref={menuRef}>
322
+ <div className={`${CommonStyles["menu-option"]} ${CommonStyles["menu-header"]}`}>
323
+ { collectionInfo.title }
324
+ </div>
325
+ {
326
+ collectionInfo.content.map((item =>
327
+ <button
328
+ key={`collection-item-${item.mediaId}`}
329
+ aria-label={`${item.title || item.mediaId} ${item.active ? "(active)" : ""}`}
330
+ role="menuitemradio"
331
+ aria-checked={item.active}
332
+ autoFocus={item.active}
333
+ onClick={() => Select(item.mediaIndex)}
334
+ className={`${CommonStyles["menu-option"]} ${item.active ? CommonStyles["menu-option-active"] : ""}`}
335
+ >
336
+ { item.title || item.mediaId }
337
+ </button>
338
+ ))
339
+ }
340
+ </div>
341
+ );
342
+ };