@grfzhl/vue-hls-player 1.1.2 → 1.1.4
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.
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
</div>
|
|
59
59
|
<slot name="before-transcripts"></slot>
|
|
60
60
|
<SubtitleBlock
|
|
61
|
+
ref="transcriptRef"
|
|
61
62
|
:subtitle="currentSubtitle"
|
|
62
63
|
:cursor="videoCursor"
|
|
63
64
|
:showTranscriptBlock="showTranscriptBlock"
|
|
@@ -144,6 +145,7 @@ const orientation = ref(null)
|
|
|
144
145
|
const autoHideIntroTitle = ref(false);
|
|
145
146
|
const initialPlayButton = ref(false);
|
|
146
147
|
const hideInitialPlayButton = ref(false)
|
|
148
|
+
const transcriptRef = ref(null)
|
|
147
149
|
const link = toRef(props, 'link');
|
|
148
150
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
149
151
|
let currentTime = 0
|
|
@@ -153,69 +155,6 @@ const videoElement = defineModel()
|
|
|
153
155
|
|
|
154
156
|
onMounted(() => {
|
|
155
157
|
prepareVideoPlayer()
|
|
156
|
-
if (video.value) {
|
|
157
|
-
|
|
158
|
-
// pass video element as reference to model
|
|
159
|
-
if (!videoElement.value) {
|
|
160
|
-
videoElement.value = video.value;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
video.value.addEventListener('timeupdate', updateCurrentTime);
|
|
164
|
-
document.addEventListener('fullscreenchange', onFullscreenChange);
|
|
165
|
-
document.addEventListener('orientationchange', onOrientationChange);
|
|
166
|
-
window.screen.orientation.addEventListener("change", onOrientationChange);
|
|
167
|
-
|
|
168
|
-
if(video.value.paused || video.value.currentTime === 0) {
|
|
169
|
-
initialPlayButton.value = true
|
|
170
|
-
|
|
171
|
-
if(props.hideInitialPlayButton) {
|
|
172
|
-
setTimeout(() => {
|
|
173
|
-
hideInitialPlayButton.value = true
|
|
174
|
-
}, 1200)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* detect initial display orientation
|
|
180
|
-
*/
|
|
181
|
-
if (typeof window.orientation === "undefined") {
|
|
182
|
-
orientation.value = window.screen.orientation.angle === 0 || window.screen.orientation.angle === 180
|
|
183
|
-
? "portrait"
|
|
184
|
-
: "landscape";
|
|
185
|
-
} else {
|
|
186
|
-
orientation.value = window.orientation === 0 || window.orientation === 180
|
|
187
|
-
? "portrait"
|
|
188
|
-
: "landscape"; // for safari
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* overwrite player.style video fullscreen button
|
|
193
|
-
* to inject own fullscreen logic
|
|
194
|
-
*/
|
|
195
|
-
const observer = new MutationObserver((mutationsList, observer) => {
|
|
196
|
-
const mediaTheme = document.querySelector('.video-player-theme-container');
|
|
197
|
-
|
|
198
|
-
if (mediaTheme && mediaTheme.shadowRoot) {
|
|
199
|
-
const fullscreenButton = mediaTheme.shadowRoot.querySelector('media-fullscreen-button');
|
|
200
|
-
const playbackRateButton = mediaTheme.shadowRoot.querySelector('media-playback-rate-menu');
|
|
201
|
-
playbackRateButton.setAttribute('rates', '0.25 0.5 0.75 1 1.5 2 3');
|
|
202
|
-
if (fullscreenButton) {
|
|
203
|
-
fullscreenButton.handleClick = async (event) => {
|
|
204
|
-
event.preventDefault();
|
|
205
|
-
event.stopPropagation();
|
|
206
|
-
event.stopImmediatePropagation();
|
|
207
|
-
startFullscreen();
|
|
208
|
-
}
|
|
209
|
-
observer.disconnect();
|
|
210
|
-
} else {
|
|
211
|
-
console.error('Button not found in Shadow DOM!');
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
console.error('Shadow Root not found!');
|
|
215
|
-
}
|
|
216
|
-
})
|
|
217
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
218
|
-
}
|
|
219
158
|
})
|
|
220
159
|
|
|
221
160
|
onUpdated(() => {
|
|
@@ -352,6 +291,11 @@ function updateCurrentTime() {
|
|
|
352
291
|
if(!video.value.paused) {
|
|
353
292
|
initialPlayButton.value = false;
|
|
354
293
|
}
|
|
294
|
+
|
|
295
|
+
// update transcripts
|
|
296
|
+
if(transcriptRef && video) {
|
|
297
|
+
transcriptRef.value.onTimeUpdate(video.value)
|
|
298
|
+
}
|
|
355
299
|
}
|
|
356
300
|
|
|
357
301
|
function toggleTranscript() {
|
|
@@ -373,7 +317,6 @@ function prepareVideoPlayer() {
|
|
|
373
317
|
hls.loadSource(stream)
|
|
374
318
|
hls.attachMedia(video.value)
|
|
375
319
|
|
|
376
|
-
hls.attachMedia(video.value)
|
|
377
320
|
video.value.muted = props.isMuted
|
|
378
321
|
video.value.currentTime = props.progress
|
|
379
322
|
|
|
@@ -415,6 +358,73 @@ function prepareVideoPlayer() {
|
|
|
415
358
|
});
|
|
416
359
|
}
|
|
417
360
|
setInterval(checkTrackModeChanges, 100);
|
|
361
|
+
initVideo();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function initVideo() {
|
|
366
|
+
if (video.value) {
|
|
367
|
+
|
|
368
|
+
// pass video element as reference to model
|
|
369
|
+
if (!videoElement.value) {
|
|
370
|
+
videoElement.value = video.value;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
video.value.addEventListener('timeupdate', updateCurrentTime);
|
|
374
|
+
document.addEventListener('fullscreenchange', onFullscreenChange);
|
|
375
|
+
document.addEventListener('orientationchange', onOrientationChange);
|
|
376
|
+
window.screen.orientation.addEventListener("change", onOrientationChange);
|
|
377
|
+
|
|
378
|
+
if(video.value.paused || video.value.currentTime === 0) {
|
|
379
|
+
initialPlayButton.value = true
|
|
380
|
+
|
|
381
|
+
if(props.hideInitialPlayButton) {
|
|
382
|
+
setTimeout(() => {
|
|
383
|
+
hideInitialPlayButton.value = true
|
|
384
|
+
}, 1200)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* detect initial display orientation
|
|
390
|
+
*/
|
|
391
|
+
if (typeof window.orientation === "undefined") {
|
|
392
|
+
orientation.value = window.screen.orientation.angle === 0 || window.screen.orientation.angle === 180
|
|
393
|
+
? "portrait"
|
|
394
|
+
: "landscape";
|
|
395
|
+
} else {
|
|
396
|
+
orientation.value = window.orientation === 0 || window.orientation === 180
|
|
397
|
+
? "portrait"
|
|
398
|
+
: "landscape"; // for safari
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* overwrite player.style video fullscreen button
|
|
403
|
+
* to inject own fullscreen logic
|
|
404
|
+
*/
|
|
405
|
+
const observer = new MutationObserver((mutationsList, observer) => {
|
|
406
|
+
const mediaTheme = document.querySelector('.video-player-theme-container');
|
|
407
|
+
|
|
408
|
+
if (mediaTheme && mediaTheme.shadowRoot) {
|
|
409
|
+
const fullscreenButton = mediaTheme.shadowRoot.querySelector('media-fullscreen-button');
|
|
410
|
+
const playbackRateButton = mediaTheme.shadowRoot.querySelector('media-playback-rate-menu');
|
|
411
|
+
playbackRateButton.setAttribute('rates', '0.25 0.5 0.75 1 1.5 2 3');
|
|
412
|
+
if (fullscreenButton) {
|
|
413
|
+
fullscreenButton.handleClick = async (event) => {
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
event.stopPropagation();
|
|
416
|
+
event.stopImmediatePropagation();
|
|
417
|
+
startFullscreen();
|
|
418
|
+
}
|
|
419
|
+
observer.disconnect();
|
|
420
|
+
} else {
|
|
421
|
+
console.error('Button not found in Shadow DOM!');
|
|
422
|
+
}
|
|
423
|
+
} else {
|
|
424
|
+
console.error('Shadow Root not found!');
|
|
425
|
+
}
|
|
426
|
+
})
|
|
427
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
418
428
|
}
|
|
419
429
|
}
|
|
420
430
|
|
|
@@ -143,7 +143,6 @@ const loadCues = async () => {
|
|
|
143
143
|
if (props.subtitle) {
|
|
144
144
|
const vttPath = props.subtitle.link;
|
|
145
145
|
const txtPath = vttPath.replace(/\.vtt$/, '.txt');
|
|
146
|
-
|
|
147
146
|
vttCues.value = await parseVTT(vttPath);
|
|
148
147
|
txtCues.value = await parseTXT(txtPath);
|
|
149
148
|
}
|
|
@@ -158,14 +157,14 @@ watch(
|
|
|
158
157
|
}
|
|
159
158
|
);
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
()
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
const onTimeUpdate = (video) => {
|
|
161
|
+
if (video) {
|
|
162
|
+
const currentTime = video.currentTime;
|
|
163
|
+
props.cursor = currentTime;
|
|
165
164
|
highlightActiveCue(currentTime);
|
|
166
|
-
checkCurrentCue(currentTime)
|
|
165
|
+
checkCurrentCue(currentTime);
|
|
167
166
|
}
|
|
168
|
-
|
|
167
|
+
};
|
|
169
168
|
|
|
170
169
|
/**
|
|
171
170
|
* highlgiht the current transcript part
|
|
@@ -223,7 +222,6 @@ function isWordActive(txtCue, word, wordIndex, txtIndex) {
|
|
|
223
222
|
|
|
224
223
|
function checkCurrentCue(currentCursor) {
|
|
225
224
|
Array.from(vttCues.value).forEach((a, index) => {
|
|
226
|
-
console.log("current cue", a)
|
|
227
225
|
if(currentCursor >= a.start && currentCursor <= a.end) {
|
|
228
226
|
currentCue.value = a.text
|
|
229
227
|
}
|
|
@@ -322,4 +320,6 @@ function secondsToTime(seconds) {
|
|
|
322
320
|
const pad = (num) => String(num).padStart(2, '0');
|
|
323
321
|
return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
|
|
324
322
|
}
|
|
323
|
+
|
|
324
|
+
defineExpose({ onTimeUpdate });
|
|
325
325
|
</script>
|