l-min-components 1.0.1117 → 1.0.1121
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "l-min-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1121",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/assets",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"draft-js": "^0.11.7",
|
|
25
25
|
"draftjs-to-html": "^0.9.1",
|
|
26
26
|
"emoji-picker-react": "^4.12.0",
|
|
27
|
+
"hls.js": "^1.5.20",
|
|
27
28
|
"html-to-draftjs": "^1.5.0",
|
|
28
29
|
"i": "^0.3.7",
|
|
29
30
|
"iso-639-1": "^3.1.2",
|
package/src/components/index.js
CHANGED
|
@@ -39,7 +39,6 @@ export { default as EnterpriseRightBar } from "./fileRightBar/enterpriseRightBar
|
|
|
39
39
|
export { default as FullPageLoader } from "./fullPageLoader";
|
|
40
40
|
export { default as AdminAppMainLayout } from "./AdminAppMainLayout";
|
|
41
41
|
export { default as PaginationComponent } from "./paginate";
|
|
42
|
-
export { default as VideoPlayer } from "./video-player";
|
|
43
42
|
export { default as AdminLogin } from "./AdminLogin";
|
|
44
43
|
export { default as AdminResetPassword } from "./AdminResetPassword";
|
|
45
44
|
export { default as AdminChangePassword } from "./AdminResetPassword/change-password";
|
|
@@ -54,3 +53,4 @@ export { default as MobileLayout } from "./mobileLayout";
|
|
|
54
53
|
export { default as useTranslation } from "../hooks/useTranslation";
|
|
55
54
|
export { default as ImageComponent } from "./ImageComponent";
|
|
56
55
|
export { default as DeveloperBanner } from "./banner/developerBanner";
|
|
56
|
+
export { default as VideoPlayer } from "./video-player";
|
|
@@ -1,66 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
useState,
|
|
3
|
+
useRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo,
|
|
7
|
+
useCallback,
|
|
8
|
+
} from "react";
|
|
2
9
|
import { OutletContext } from "../AppMainLayout";
|
|
10
|
+
import FullPageLoader from "../fullPageLoader";
|
|
3
11
|
import screenfull from "screenfull";
|
|
12
|
+
import Hls from "hls.js";
|
|
4
13
|
import {
|
|
5
14
|
LoadingScreen,
|
|
6
15
|
RangeContainer,
|
|
7
16
|
VideoController,
|
|
8
17
|
VideoPlayerContainer,
|
|
9
|
-
VideoPrompts,
|
|
10
18
|
} from "./index.styled";
|
|
11
|
-
import ReactPlayer from "react-player";
|
|
12
19
|
import VideoScreenIcon from "./icons/videoScreenIcon";
|
|
13
20
|
import PlayIcon from "./icons/playVideoIcon";
|
|
14
21
|
import PauseIcon from "./icons/pause";
|
|
15
|
-
// import LoaderCustom from "../loader";
|
|
16
|
-
import FullPageLoader from "../fullPageLoader";
|
|
17
22
|
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @param {object} props
|
|
21
|
-
* @param {string} props.width - Width of the player in px
|
|
22
|
-
* @param {string} props.height - Height of the player in px
|
|
23
|
-
* @param {React.CSSProperties} props.style - Player container style
|
|
24
|
-
* @param {boolean} props.hideRange - To hide the range controller
|
|
25
|
-
* @param {boolean} props.showPrompts - show next and prev controller
|
|
26
|
-
* @param {string} props.src - Video source url
|
|
27
|
-
* @param {string} props.streamUrl - Stream video url
|
|
28
|
-
* @param {string} props.thumbnailSrc - Thumbnail url
|
|
29
|
-
* @returns {JSX.Element}
|
|
30
|
-
*/
|
|
31
23
|
const VideoPlayer = ({
|
|
32
24
|
width,
|
|
33
25
|
height = "360px",
|
|
34
26
|
style,
|
|
35
27
|
hideRange,
|
|
36
28
|
showPrompts,
|
|
29
|
+
controlSize,
|
|
37
30
|
src,
|
|
38
31
|
streamUrl,
|
|
39
|
-
|
|
32
|
+
small,
|
|
40
33
|
}) => {
|
|
41
|
-
const [isPlaying,
|
|
34
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
42
35
|
const [isSeeking, setIsSeeking] = useState(false);
|
|
36
|
+
const [error, setError] = useState(null);
|
|
43
37
|
const [progress, setProgress] = useState();
|
|
44
38
|
const [hideController, setHideController] = useState(false);
|
|
45
39
|
const [count, setCount] = useState(0);
|
|
46
|
-
const playContainerRef = useRef();
|
|
47
|
-
const [url, setUrl] = useState(null);
|
|
48
|
-
const [image, setImage] = useState(null);
|
|
49
|
-
const playerRef = useRef();
|
|
50
|
-
const { accessToken } = useContext(OutletContext);
|
|
51
40
|
const [isReady, setIsReady] = useState(false);
|
|
52
41
|
const [rangeProgress, setRangeProgress] = useState(0);
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
if (thumbnailSrc) {
|
|
59
|
-
setImage(thumbnailSrc);
|
|
60
|
-
}
|
|
61
|
-
}, [streamUrl, thumbnailSrc, src]);
|
|
43
|
+
const playContainerRef = useRef();
|
|
44
|
+
const videoRef = useRef();
|
|
45
|
+
const { accessToken, generalData } = useContext(OutletContext);
|
|
62
46
|
|
|
63
|
-
const
|
|
47
|
+
const accountId = generalData?.selectedAccount?.id;
|
|
48
|
+
const url = useMemo(() => src || `${streamUrl}`, [src, streamUrl]);
|
|
49
|
+
|
|
50
|
+
const formatTime = useCallback((secs) => {
|
|
64
51
|
const sec_num = parseInt(secs, 10);
|
|
65
52
|
const hours = Math.floor(sec_num / 3600);
|
|
66
53
|
const minutes = Math.floor(sec_num / 60) % 60;
|
|
@@ -69,18 +56,22 @@ const VideoPlayer = ({
|
|
|
69
56
|
return [hours, minutes, seconds]
|
|
70
57
|
.map((v) => (v < 10 ? "0" + v : v))
|
|
71
58
|
.join(":");
|
|
72
|
-
};
|
|
59
|
+
}, []);
|
|
73
60
|
|
|
74
|
-
const handlePlayPause = () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
const handlePlayPause = useCallback(() => {
|
|
62
|
+
setIsPlaying((prev) => !prev);
|
|
63
|
+
if (videoRef.current) {
|
|
64
|
+
isPlaying ? videoRef.current.pause() : videoRef.current.play();
|
|
65
|
+
}
|
|
66
|
+
}, [isPlaying]);
|
|
78
67
|
|
|
79
|
-
const handleFullScreen = () => {
|
|
80
|
-
screenfull.
|
|
81
|
-
|
|
68
|
+
const handleFullScreen = useCallback(() => {
|
|
69
|
+
if (screenfull.isEnabled) {
|
|
70
|
+
screenfull.toggle(playContainerRef.current);
|
|
71
|
+
}
|
|
72
|
+
}, []);
|
|
82
73
|
|
|
83
|
-
const handleProgress = (
|
|
74
|
+
const handleProgress = useCallback(() => {
|
|
84
75
|
if (count > 3) {
|
|
85
76
|
setHideController(true);
|
|
86
77
|
setCount(0);
|
|
@@ -88,11 +79,15 @@ const VideoPlayer = ({
|
|
|
88
79
|
if (!hideController) {
|
|
89
80
|
setCount(count + 1);
|
|
90
81
|
}
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
if (videoRef?.current) {
|
|
83
|
+
const currentTime = videoRef.current.currentTime;
|
|
84
|
+
const duration = videoRef.current.duration;
|
|
85
|
+
const played = currentTime / duration;
|
|
86
|
+
|
|
87
|
+
setRangeProgress(played);
|
|
88
|
+
setProgress({ played, currentTime, duration });
|
|
94
89
|
}
|
|
95
|
-
};
|
|
90
|
+
}, [isSeeking, count, hideController]);
|
|
96
91
|
|
|
97
92
|
const handleSeekChange = (e) => {
|
|
98
93
|
const value = parseFloat(e.target.value) / 100;
|
|
@@ -101,7 +96,9 @@ const VideoPlayer = ({
|
|
|
101
96
|
|
|
102
97
|
const handleSeekMouseUp = () => {
|
|
103
98
|
setIsSeeking(false);
|
|
104
|
-
|
|
99
|
+
if (videoRef.current) {
|
|
100
|
+
videoRef.current.currentTime = rangeProgress * videoRef.current.duration;
|
|
101
|
+
}
|
|
105
102
|
};
|
|
106
103
|
|
|
107
104
|
const handleSeekMouseDown = () => {
|
|
@@ -113,29 +110,56 @@ const VideoPlayer = ({
|
|
|
113
110
|
setCount(0);
|
|
114
111
|
};
|
|
115
112
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
let hls;
|
|
115
|
+
|
|
116
|
+
if (videoRef.current && accountId) {
|
|
117
|
+
if (!src && streamUrl && Hls.isSupported()) {
|
|
118
|
+
hls = new Hls({
|
|
119
|
+
xhrSetup: function (xhr, url) {
|
|
120
|
+
const modifiedURL = `${url}?_account=${accountId}`;
|
|
121
|
+
xhr.open("GET", modifiedURL, true);
|
|
122
|
+
xhr.setRequestHeader("Authorization", `Bearer ${accessToken}`);
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
hls.loadSource(url);
|
|
126
|
+
hls.attachMedia(videoRef.current);
|
|
127
|
+
|
|
128
|
+
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
|
129
|
+
setIsReady(true);
|
|
130
|
+
setError(null);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
hls.on(Hls.Events.ERROR, (event, data) => {
|
|
134
|
+
if (data?.response?.code === 400) {
|
|
135
|
+
setError("This resource is being processed, please try again late");
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
} else if (
|
|
139
|
+
videoRef.current.canPlayType("application/vnd.apple.mpegurl") &&
|
|
140
|
+
!src
|
|
141
|
+
) {
|
|
142
|
+
videoRef.current.src = url;
|
|
143
|
+
videoRef.current.addEventListener("loadedmetadata", () => {
|
|
144
|
+
setIsReady(true);
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
if (videoRef.current && src) {
|
|
148
|
+
videoRef.current.src = src;
|
|
149
|
+
|
|
150
|
+
videoRef.current.load();
|
|
151
|
+
setIsReady(true);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
121
154
|
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const currentTime = playerRef.current?.getCurrentTime()
|
|
125
|
-
? format(playerRef.current?.getCurrentTime())
|
|
126
|
-
: "00:00:00";
|
|
127
155
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
if (progress?.loaded) {
|
|
134
|
-
setIsReady(true);
|
|
135
|
-
} else {
|
|
156
|
+
return () => {
|
|
157
|
+
if (hls) {
|
|
158
|
+
hls.destroy();
|
|
159
|
+
}
|
|
136
160
|
setIsReady(false);
|
|
137
|
-
}
|
|
138
|
-
}, [
|
|
161
|
+
};
|
|
162
|
+
}, [url, accountId, accessToken, videoRef?.current]);
|
|
139
163
|
|
|
140
164
|
return (
|
|
141
165
|
<VideoPlayerContainer
|
|
@@ -145,72 +169,37 @@ const VideoPlayer = ({
|
|
|
145
169
|
height={height}
|
|
146
170
|
onMouseMove={handleMouseMove}
|
|
147
171
|
>
|
|
148
|
-
{
|
|
149
|
-
<VideoPrompts>
|
|
150
|
-
<div>
|
|
151
|
-
<p>Continue watching</p>
|
|
152
|
-
<p>Previuos Part (Lesson 1)</p>
|
|
153
|
-
</div>
|
|
154
|
-
<div>
|
|
155
|
-
<p>Continue watching</p>
|
|
156
|
-
<p>Next Part (Lesson 6)</p>
|
|
157
|
-
</div>
|
|
158
|
-
</VideoPrompts>
|
|
159
|
-
)}
|
|
160
|
-
{!isReady && !image && (
|
|
172
|
+
{!isReady && (
|
|
161
173
|
<LoadingScreen>
|
|
162
|
-
|
|
163
|
-
|
|
174
|
+
<FullPageLoader
|
|
175
|
+
isSectionLoader
|
|
176
|
+
hasBackground
|
|
177
|
+
loaderWidth={small ? 150 : 200}
|
|
178
|
+
loaderHeight={small ? 150 : 200}
|
|
179
|
+
zIndex={5}
|
|
180
|
+
/>
|
|
181
|
+
|
|
182
|
+
{error && <p className={`error ${small ? "sm" : ""}`}>{error}</p>}
|
|
164
183
|
</LoadingScreen>
|
|
165
184
|
)}
|
|
166
|
-
|
|
185
|
+
|
|
186
|
+
<video
|
|
187
|
+
ref={videoRef}
|
|
167
188
|
width="100%"
|
|
168
|
-
ref={playerRef}
|
|
169
189
|
height="100%"
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
playing={isPlaying}
|
|
175
|
-
onProgress={handleProgress}
|
|
176
|
-
onEnded={() => {
|
|
177
|
-
setIsPlayering(false);
|
|
178
|
-
setHideController(false);
|
|
179
|
-
setCount(0);
|
|
180
|
-
setProgress({ ...progress, played: 1 });
|
|
190
|
+
onTimeUpdate={handleProgress}
|
|
191
|
+
controls={false}
|
|
192
|
+
onCanPlay={() => {
|
|
193
|
+
setIsReady(true);
|
|
181
194
|
}}
|
|
182
|
-
config={
|
|
183
|
-
streamUrl
|
|
184
|
-
? {
|
|
185
|
-
file: {
|
|
186
|
-
forceHLS: true,
|
|
187
|
-
hlsOptions: {
|
|
188
|
-
xhrSetup: function (xhr, url) {
|
|
189
|
-
if (accessToken) {
|
|
190
|
-
const modifiedURL = `${url}?_account=7d5529dcf5`;
|
|
191
|
-
xhr.open("GET", modifiedURL, true);
|
|
192
|
-
xhr.setRequestHeader(
|
|
193
|
-
"Authorization",
|
|
194
|
-
`Bearer ${accessToken}`,
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
hls: {
|
|
201
|
-
enableLowInitialLatency: true,
|
|
202
|
-
smoothQualityChange: true,
|
|
203
|
-
startLevel: 0,
|
|
204
|
-
},
|
|
205
|
-
}
|
|
206
|
-
: { file: null, hls: null }
|
|
207
|
-
}
|
|
208
195
|
/>
|
|
209
|
-
|
|
210
|
-
|
|
196
|
+
|
|
197
|
+
<VideoController hide={hideController} size={controlSize}>
|
|
198
|
+
{!hideRange && (
|
|
211
199
|
<RangeContainer>
|
|
212
200
|
<p>
|
|
213
|
-
{currentTime} /
|
|
201
|
+
{formatTime(progress?.currentTime || 0)} /{" "}
|
|
202
|
+
{formatTime(progress?.duration || 0)}
|
|
214
203
|
</p>
|
|
215
204
|
<input
|
|
216
205
|
type="range"
|
|
@@ -225,7 +214,7 @@ const VideoPlayer = ({
|
|
|
225
214
|
<VideoScreenIcon onClick={handleFullScreen} />
|
|
226
215
|
</RangeContainer>
|
|
227
216
|
)}
|
|
228
|
-
{
|
|
217
|
+
{isReady && (
|
|
229
218
|
<div className="play_pause_wrap" onClick={handlePlayPause}>
|
|
230
219
|
{isPlaying ? <PauseIcon fill="#fff" /> : <PlayIcon fill="#fff" />}
|
|
231
220
|
</div>
|
|
@@ -63,9 +63,12 @@ export const RangeContainer = styled.div`
|
|
|
63
63
|
.range {
|
|
64
64
|
border-radius: 9px;
|
|
65
65
|
flex: 1;
|
|
66
|
+
width: 100%;
|
|
67
|
+
display: block;
|
|
66
68
|
-webkit-appearance: none;
|
|
67
69
|
appearance: none;
|
|
68
70
|
overflow: hidden;
|
|
71
|
+
cursor: pointer;
|
|
69
72
|
&::-webkit-slider-runnable-track {
|
|
70
73
|
height: 15px;
|
|
71
74
|
background: rgba(198, 204, 204, 0.4);
|
|
@@ -156,6 +159,23 @@ export const LoadingScreen = styled.div`
|
|
|
156
159
|
bottom: 0;
|
|
157
160
|
z-index: 40;
|
|
158
161
|
background-color: rgba(0, 0, 0, 0.05);
|
|
159
|
-
display:
|
|
160
|
-
|
|
162
|
+
display: flex;
|
|
163
|
+
flex-direction: column;
|
|
164
|
+
justify-content: flex-end;
|
|
165
|
+
|
|
166
|
+
align-items: center;
|
|
167
|
+
gap: 12px;
|
|
168
|
+
.error {
|
|
169
|
+
color: #f95454;
|
|
170
|
+
text-align: center;
|
|
171
|
+
padding: 0 16px;
|
|
172
|
+
font-size: 14px;
|
|
173
|
+
font-style: italic;
|
|
174
|
+
font-weight: 500;
|
|
175
|
+
margin-bottom: 100px;
|
|
176
|
+
&.sm {
|
|
177
|
+
font-size: 12px;
|
|
178
|
+
margin-bottom: 16px;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
161
181
|
`;
|