@grfzhl/vue-hls-player 1.0.20 → 1.1.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/README.md
CHANGED
|
@@ -73,6 +73,17 @@ For **nuxt 3**, try to wrap this component in ClientOnly, images for previewImag
|
|
|
73
73
|
</ClientOnly>
|
|
74
74
|
```
|
|
75
75
|
### Props:
|
|
76
|
+
**fullScreenElement**:
|
|
77
|
+
1. value: 'hls-player-media-container', type: String
|
|
78
|
+
|
|
79
|
+
If you need to provide additional UI in fullscreen mode
|
|
80
|
+
you can input a parent wrapper of your player to show
|
|
81
|
+
in fullscreen
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
fullScreenElement="demo"
|
|
85
|
+
```
|
|
86
|
+
|
|
76
87
|
**type**:
|
|
77
88
|
1. value: 'default', type: String
|
|
78
89
|
|
|
@@ -124,17 +135,11 @@ const fullScreenAction = (fullScreenElement) => {
|
|
|
124
135
|
```
|
|
125
136
|
|
|
126
137
|
**@video-fullscreen-action**:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
document.exitFullscreen();
|
|
133
|
-
} else {
|
|
134
|
-
document.getElementById("video-container").requestFullscreen()
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
+
Removed in the 1.1.0 version.
|
|
139
|
+
It caused too much problems with mobile devices.
|
|
140
|
+
Now you can pass the desired element id to open
|
|
141
|
+
fullscreen with prop: fullScreenElement
|
|
142
|
+
|
|
138
143
|
**showTranscriptBlock**:
|
|
139
144
|
1. value: true or false, type: Boolean
|
|
140
145
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
<video
|
|
23
23
|
class="hls-player"
|
|
24
24
|
slot="media"
|
|
25
|
+
:key="link"
|
|
25
26
|
@pause="pause"
|
|
26
27
|
@keyup="changeSpeed"
|
|
27
28
|
@ended="onVideoEnd"
|
|
@@ -127,10 +128,14 @@ const props = defineProps({
|
|
|
127
128
|
hideInitialPlayButton: {
|
|
128
129
|
type: Boolean,
|
|
129
130
|
default: false
|
|
131
|
+
},
|
|
132
|
+
fullScreenElement: {
|
|
133
|
+
type: String,
|
|
134
|
+
default: 'hls-player-media-container'
|
|
130
135
|
}
|
|
131
136
|
})
|
|
132
137
|
|
|
133
|
-
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'
|
|
138
|
+
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'])
|
|
134
139
|
const video = ref(null)
|
|
135
140
|
const subtitlesContainer = ref(null)
|
|
136
141
|
const currentSubtitleLang = ref(null)
|
|
@@ -142,7 +147,8 @@ const initialPlayButton = ref(false);
|
|
|
142
147
|
const hideInitialPlayButton = ref(false)
|
|
143
148
|
const link = toRef(props, 'link');
|
|
144
149
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
145
|
-
let
|
|
150
|
+
let currentTime = 0
|
|
151
|
+
let hls = null
|
|
146
152
|
|
|
147
153
|
const videoElement = defineModel()
|
|
148
154
|
|
|
@@ -199,7 +205,7 @@ onMounted(() => {
|
|
|
199
205
|
event.preventDefault();
|
|
200
206
|
event.stopPropagation();
|
|
201
207
|
event.stopImmediatePropagation();
|
|
202
|
-
|
|
208
|
+
startFullscreen();
|
|
203
209
|
}
|
|
204
210
|
observer.disconnect();
|
|
205
211
|
} else {
|
|
@@ -251,17 +257,61 @@ watch([props, videoElement], (a) => {
|
|
|
251
257
|
}
|
|
252
258
|
})
|
|
253
259
|
|
|
254
|
-
watch(link, (
|
|
255
|
-
|
|
260
|
+
watch(link, (newLink, oldLink) => {
|
|
261
|
+
if (newLink !== oldLink) {
|
|
262
|
+
console.log("prepare new src " + newLink)
|
|
263
|
+
prepareVideoPlayer();
|
|
264
|
+
}
|
|
256
265
|
})
|
|
257
266
|
|
|
267
|
+
async function startFullscreen() {
|
|
268
|
+
let vpVideoBlock = document.getElementById(props.fullScreenElement);
|
|
269
|
+
if(video.value) {
|
|
270
|
+
currentTime = video.value.currentTime
|
|
271
|
+
}
|
|
272
|
+
if (document.fullscreenElement) {
|
|
273
|
+
if (screen.orientation && screen.orientation.unlock) {
|
|
274
|
+
screen.orientation.unlock();
|
|
275
|
+
}
|
|
276
|
+
await document.exitFullscreen();
|
|
277
|
+
isFullscreen.value = false;
|
|
278
|
+
} else {
|
|
279
|
+
isFullscreen.value = true;
|
|
280
|
+
try {
|
|
281
|
+
if (vpVideoBlock.requestFullscreen) {
|
|
282
|
+
await vpVideoBlock.requestFullscreen();
|
|
283
|
+
} else if (vpVideoBlock.webkitRequestFullscreen) {
|
|
284
|
+
vpVideoBlock = document.querySelector('video');
|
|
285
|
+
await vpVideoBlock.webkitRequestFullscreen(); // Safari
|
|
286
|
+
} else if (vpVideoBlock.mozRequestFullScreen) {
|
|
287
|
+
await vpVideoBlock.mozRequestFullScreen(); // Firefox
|
|
288
|
+
} else if (vpVideoBlock.msRequestFullscreen) {
|
|
289
|
+
await vpVideoBlock.msRequestFullscreen(); // IE/Edge
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (screen.orientation && screen.orientation.lock) {
|
|
293
|
+
try {
|
|
294
|
+
await screen.orientation.lock("landscape");
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.warn("Orientation lock failed", error);
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
console.warn("Orientation lock not supported.");
|
|
300
|
+
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error("Fullscreen could not be activated", error);
|
|
303
|
+
isFullscreen.value = false;
|
|
304
|
+
}
|
|
305
|
+
video.value.currentTime = currentTime;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
258
309
|
function onSubtitleError(link) {
|
|
259
310
|
console.error(`Error on loading subtitles: ${link}`);
|
|
260
311
|
}
|
|
261
312
|
|
|
262
|
-
function onFullscreenChange() {
|
|
263
|
-
|
|
264
|
-
emit('video-fullscreen-change', document.fullscreenElement)
|
|
313
|
+
function onFullscreenChange(e) {
|
|
314
|
+
e.preventDefault();
|
|
265
315
|
|
|
266
316
|
// hide intro title after x seconds
|
|
267
317
|
if(isFullscreen.value === true) {
|
|
@@ -271,6 +321,7 @@ function onFullscreenChange() {
|
|
|
271
321
|
} else {
|
|
272
322
|
autoHideIntroTitle.value = false;
|
|
273
323
|
}
|
|
324
|
+
isFullscreen.value = !!document.fullscreenElement;
|
|
274
325
|
};
|
|
275
326
|
|
|
276
327
|
function onOrientationChange(e) {
|
|
@@ -284,10 +335,17 @@ function onOrientationChange(e) {
|
|
|
284
335
|
orientation.value = angle === 0 || angle === 180
|
|
285
336
|
? "portrait"
|
|
286
337
|
: "landscape";
|
|
287
|
-
}
|
|
288
338
|
|
|
289
|
-
|
|
290
|
-
|
|
339
|
+
let isPortrait = angle === 0 || angle === 180;
|
|
340
|
+
let isLandscape = angle === 90 || angle === -90;
|
|
341
|
+
|
|
342
|
+
if (isFullscreen.value && isPortrait) {
|
|
343
|
+
setTimeout(async () => {
|
|
344
|
+
if (!document.fullscreenElement) {
|
|
345
|
+
startFullscreen();
|
|
346
|
+
}
|
|
347
|
+
}, 700);
|
|
348
|
+
}
|
|
291
349
|
}
|
|
292
350
|
|
|
293
351
|
function updateCurrentTime() {
|
|
@@ -307,11 +365,15 @@ function seekVideo(time) {
|
|
|
307
365
|
}
|
|
308
366
|
|
|
309
367
|
function prepareVideoPlayer() {
|
|
310
|
-
let stream = props.link
|
|
311
|
-
hls.loadSource(stream)
|
|
312
|
-
hls.attachMedia(video.value)
|
|
313
|
-
|
|
314
368
|
if (video.value) {
|
|
369
|
+
if (hls) {
|
|
370
|
+
hls.destroy();
|
|
371
|
+
}
|
|
372
|
+
hls = new Hls();
|
|
373
|
+
let stream = props.link
|
|
374
|
+
hls.loadSource(stream)
|
|
375
|
+
hls.attachMedia(video.value)
|
|
376
|
+
|
|
315
377
|
hls.attachMedia(video.value)
|
|
316
378
|
video.value.muted = props.isMuted
|
|
317
379
|
video.value.currentTime = props.progress
|
|
@@ -375,6 +437,8 @@ function changeSpeed(e) {
|
|
|
375
437
|
video.value.playbackRate = video.value.playbackRate - 0.25
|
|
376
438
|
}
|
|
377
439
|
}
|
|
440
|
+
defineExpose({ startFullscreen });
|
|
441
|
+
|
|
378
442
|
</script>
|
|
379
443
|
<style>
|
|
380
444
|
video::cue {
|
|
@@ -207,11 +207,13 @@ function isTxtCueActive(txtCue) {
|
|
|
207
207
|
* @param txtIndex
|
|
208
208
|
*/
|
|
209
209
|
function isWordActive(txtCue, word, wordIndex, txtIndex) {
|
|
210
|
+
console.log("check word active ", txtCue, word, wordIndex, txtIndex)
|
|
210
211
|
if(!currentCue.value || !word || !txtCue) {
|
|
211
212
|
return false
|
|
212
213
|
}
|
|
213
214
|
const startPos = txtCue.dialog[0].text.indexOf(currentCue.value)
|
|
214
215
|
const endPos = startPos + currentCue.value.length
|
|
216
|
+
console.log("can word marked", startPos, endPos, wordIndex)
|
|
215
217
|
if(wordIndex >= startPos && wordIndex < endPos) {
|
|
216
218
|
return true;
|
|
217
219
|
}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
@pause="pause"
|
|
15
15
|
@video-ended="onVideoEnd"
|
|
16
16
|
@video-fullscreen-change="onFullscreenChange"
|
|
17
|
-
@video-fullscreen-action="oVideoFullscreenAction"
|
|
18
17
|
v-model="videoElement"
|
|
18
|
+
ref="childRef"
|
|
19
19
|
>
|
|
20
20
|
<template v-slot:before-media><slot name="before-media"></slot></template>
|
|
21
21
|
<template v-slot:after-media><slot name="after-media"></slot></template>
|
|
@@ -28,9 +28,10 @@
|
|
|
28
28
|
import BasePlayer from './BasePlayer.vue'
|
|
29
29
|
import { ref, toRef } from 'vue'
|
|
30
30
|
|
|
31
|
-
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'
|
|
31
|
+
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'])
|
|
32
32
|
|
|
33
33
|
const videoElement = ref(null);
|
|
34
|
+
const childRef = ref(null)
|
|
34
35
|
|
|
35
36
|
const props = defineProps({
|
|
36
37
|
previewImageLink: {
|
|
@@ -72,12 +73,18 @@ const props = defineProps({
|
|
|
72
73
|
hideInitialPlayButton: {
|
|
73
74
|
type: Boolean,
|
|
74
75
|
default: false
|
|
76
|
+
},
|
|
77
|
+
fullScreenElement: {
|
|
78
|
+
type: String,
|
|
79
|
+
default: 'hls-player-media-container'
|
|
75
80
|
}
|
|
76
81
|
})
|
|
77
82
|
|
|
78
83
|
const link = toRef(props, 'link');
|
|
79
84
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
80
85
|
|
|
86
|
+
defineExpose({ startFullscreen });
|
|
87
|
+
|
|
81
88
|
function pause(currentTime) {
|
|
82
89
|
emit('pause', currentTime)
|
|
83
90
|
}
|
|
@@ -91,7 +98,7 @@ function onFullscreenChange(data) {
|
|
|
91
98
|
emit('video-fullscreen-change', data);
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
function
|
|
95
|
-
|
|
101
|
+
function startFullscreen() {
|
|
102
|
+
childRef.value.startFullscreen();
|
|
96
103
|
}
|
|
97
104
|
</script>
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
@pause="pause"
|
|
5
5
|
@video-fullscreen-change="onVideoFullScreenChange"
|
|
6
6
|
@video-ended="onVideoEnd"
|
|
7
|
-
@video-fullscreen-action="oVideoFullscreenAction"
|
|
8
7
|
:introTitle="introTitle"
|
|
9
8
|
:previewImageLink="previewImageLink"
|
|
10
9
|
:showTranscriptBlock="showTranscriptBlock"
|
|
@@ -14,6 +13,7 @@
|
|
|
14
13
|
:isMuted="isMuted"
|
|
15
14
|
:autoplay="autoplay"
|
|
16
15
|
v-model="videoElement"
|
|
16
|
+
ref="childRef"
|
|
17
17
|
:hideInitialPlayButton="hideInitialPlayButton"
|
|
18
18
|
>
|
|
19
19
|
<template v-slot:before-media><slot name="before-media"></slot></template>
|
|
@@ -37,6 +37,7 @@ import { ref, toRef } from 'vue'
|
|
|
37
37
|
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change', 'video-fullscreen-action'])
|
|
38
38
|
|
|
39
39
|
const videoElement = ref(null);
|
|
40
|
+
const childRef = ref(null)
|
|
40
41
|
|
|
41
42
|
const props = defineProps({
|
|
42
43
|
previewImageLink: {
|
|
@@ -82,12 +83,18 @@ const props = defineProps({
|
|
|
82
83
|
hideInitialPlayButton: {
|
|
83
84
|
type: Boolean,
|
|
84
85
|
default: false
|
|
86
|
+
},
|
|
87
|
+
fullScreenElement: {
|
|
88
|
+
type: String,
|
|
89
|
+
default: 'hls-player-media-container'
|
|
85
90
|
}
|
|
86
91
|
})
|
|
87
92
|
|
|
88
93
|
const link = toRef(props, 'link');
|
|
89
94
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
90
95
|
|
|
96
|
+
defineExpose({ startFullscreen });
|
|
97
|
+
|
|
91
98
|
function pause(currentTime) {
|
|
92
99
|
emit('pause', currentTime)
|
|
93
100
|
}
|
|
@@ -97,7 +104,7 @@ function onVideoFullScreenChange(data) {
|
|
|
97
104
|
function onVideoEnd(data) {
|
|
98
105
|
emit('video-ended', data);
|
|
99
106
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
107
|
+
function startFullscreen() {
|
|
108
|
+
childRef.value.startFullscreen();
|
|
102
109
|
}
|
|
103
110
|
</script>
|