@grfzhl/vue-hls-player 1.0.19 → 1.1.0
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 +16 -11
- package/dist/VideoPlayer/BasePlayer.vue +83 -14
- package/dist/VideoPlayer/VDefaultVideoPlayer.vue +11 -4
- package/dist/VideoPlayer/index.vue +10 -3
- package/package.json +1 -1
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"
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
:src="subtitle.link"
|
|
47
48
|
kind="subtitles"
|
|
48
49
|
:srclang="subtitle.lang"
|
|
50
|
+
@error="onSubtitleError(subtitle.link)"
|
|
49
51
|
:label="subtitle.label" :default="i === 0" />
|
|
50
52
|
</video>
|
|
51
53
|
</media-theme-sutro>
|
|
@@ -126,10 +128,14 @@ const props = defineProps({
|
|
|
126
128
|
hideInitialPlayButton: {
|
|
127
129
|
type: Boolean,
|
|
128
130
|
default: false
|
|
131
|
+
},
|
|
132
|
+
fullScreenElement: {
|
|
133
|
+
type: String,
|
|
134
|
+
default: 'hls-player-media-container'
|
|
129
135
|
}
|
|
130
136
|
})
|
|
131
137
|
|
|
132
|
-
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'
|
|
138
|
+
const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'])
|
|
133
139
|
const video = ref(null)
|
|
134
140
|
const subtitlesContainer = ref(null)
|
|
135
141
|
const currentSubtitleLang = ref(null)
|
|
@@ -141,6 +147,8 @@ const initialPlayButton = ref(false);
|
|
|
141
147
|
const hideInitialPlayButton = ref(false)
|
|
142
148
|
const link = toRef(props, 'link');
|
|
143
149
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
150
|
+
let currentTime = 0
|
|
151
|
+
let hls = new Hls()
|
|
144
152
|
|
|
145
153
|
const videoElement = defineModel()
|
|
146
154
|
|
|
@@ -197,7 +205,7 @@ onMounted(() => {
|
|
|
197
205
|
event.preventDefault();
|
|
198
206
|
event.stopPropagation();
|
|
199
207
|
event.stopImmediatePropagation();
|
|
200
|
-
|
|
208
|
+
startFullscreen();
|
|
201
209
|
}
|
|
202
210
|
observer.disconnect();
|
|
203
211
|
} else {
|
|
@@ -218,10 +226,10 @@ onUpdated(() => {
|
|
|
218
226
|
onUnmounted(() => {
|
|
219
227
|
if (video.value) {
|
|
220
228
|
video.value.removeEventListener('timeupdate', updateCurrentTime);
|
|
221
|
-
document.removeEventListener('fullscreenchange', onFullscreenChange);
|
|
222
|
-
document.removeEventListener('orientationchange', onOrientationChange);
|
|
223
|
-
window.screen.orientation.addEventListener("change", onOrientationChange);
|
|
224
229
|
}
|
|
230
|
+
document.removeEventListener('fullscreenchange', onFullscreenChange);
|
|
231
|
+
document.removeEventListener('orientationchange', onOrientationChange);
|
|
232
|
+
window.screen.orientation.removeEventListener("change", onOrientationChange);
|
|
225
233
|
});
|
|
226
234
|
|
|
227
235
|
const mutedAttr = computed(() => {
|
|
@@ -240,18 +248,69 @@ const currentSubtitle = computed(() => {
|
|
|
240
248
|
})
|
|
241
249
|
|
|
242
250
|
watch([props, videoElement], (a) => {
|
|
243
|
-
if(a[0].autoplay && a[1]) {
|
|
251
|
+
if(a[0].autoplay && a[1] && a[1].paused) {
|
|
244
252
|
// autoplay is only possible when muted
|
|
245
253
|
a[1].muted = true
|
|
246
254
|
setTimeout(() => {
|
|
247
|
-
a[1].play();
|
|
255
|
+
a[1].play().catch(err => console.warn("Autoplay-Error:", err));
|
|
248
256
|
}, 200)
|
|
249
257
|
}
|
|
250
258
|
})
|
|
251
259
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
260
|
+
watch(link, (newLink, oldLink) => {
|
|
261
|
+
if (newLink !== oldLink) {
|
|
262
|
+
prepareVideoPlayer();
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
async function startFullscreen() {
|
|
267
|
+
let vpVideoBlock = document.getElementById(props.fullScreenElement);
|
|
268
|
+
if(video.value) {
|
|
269
|
+
currentTime = video.value.currentTime
|
|
270
|
+
}
|
|
271
|
+
if (document.fullscreenElement) {
|
|
272
|
+
if (screen.orientation && screen.orientation.unlock) {
|
|
273
|
+
screen.orientation.unlock();
|
|
274
|
+
}
|
|
275
|
+
await document.exitFullscreen();
|
|
276
|
+
isFullscreen.value = false;
|
|
277
|
+
} else {
|
|
278
|
+
isFullscreen.value = true;
|
|
279
|
+
try {
|
|
280
|
+
if (vpVideoBlock.requestFullscreen) {
|
|
281
|
+
await vpVideoBlock.requestFullscreen();
|
|
282
|
+
} else if (vpVideoBlock.webkitRequestFullscreen) {
|
|
283
|
+
vpVideoBlock = document.querySelector('video');
|
|
284
|
+
await vpVideoBlock.webkitRequestFullscreen(); // Safari
|
|
285
|
+
} else if (vpVideoBlock.mozRequestFullScreen) {
|
|
286
|
+
await vpVideoBlock.mozRequestFullScreen(); // Firefox
|
|
287
|
+
} else if (vpVideoBlock.msRequestFullscreen) {
|
|
288
|
+
await vpVideoBlock.msRequestFullscreen(); // IE/Edge
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (screen.orientation && screen.orientation.lock) {
|
|
292
|
+
try {
|
|
293
|
+
await screen.orientation.lock("landscape");
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.warn("Orientation lock failed", error);
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
console.warn("Orientation lock not supported.");
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error("Fullscreen could not be activated", error);
|
|
302
|
+
isFullscreen.value = false;
|
|
303
|
+
}
|
|
304
|
+
video.value.currentTime = currentTime;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function onSubtitleError(link) {
|
|
309
|
+
console.error(`Error on loading subtitles: ${link}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function onFullscreenChange(e) {
|
|
313
|
+
e.preventDefault();
|
|
255
314
|
|
|
256
315
|
// hide intro title after x seconds
|
|
257
316
|
if(isFullscreen.value === true) {
|
|
@@ -261,6 +320,7 @@ function onFullscreenChange() {
|
|
|
261
320
|
} else {
|
|
262
321
|
autoHideIntroTitle.value = false;
|
|
263
322
|
}
|
|
323
|
+
isFullscreen.value = !!document.fullscreenElement;
|
|
264
324
|
};
|
|
265
325
|
|
|
266
326
|
function onOrientationChange(e) {
|
|
@@ -274,10 +334,17 @@ function onOrientationChange(e) {
|
|
|
274
334
|
orientation.value = angle === 0 || angle === 180
|
|
275
335
|
? "portrait"
|
|
276
336
|
: "landscape";
|
|
277
|
-
}
|
|
278
337
|
|
|
279
|
-
|
|
280
|
-
|
|
338
|
+
let isPortrait = angle === 0 || angle === 180;
|
|
339
|
+
let isLandscape = angle === 90 || angle === -90;
|
|
340
|
+
|
|
341
|
+
if (isFullscreen.value && isPortrait) {
|
|
342
|
+
setTimeout(async () => {
|
|
343
|
+
if (!document.fullscreenElement) {
|
|
344
|
+
startFullscreen();
|
|
345
|
+
}
|
|
346
|
+
}, 700);
|
|
347
|
+
}
|
|
281
348
|
}
|
|
282
349
|
|
|
283
350
|
function updateCurrentTime() {
|
|
@@ -297,9 +364,9 @@ function seekVideo(time) {
|
|
|
297
364
|
}
|
|
298
365
|
|
|
299
366
|
function prepareVideoPlayer() {
|
|
300
|
-
let hls = new Hls()
|
|
301
367
|
let stream = props.link
|
|
302
368
|
hls.loadSource(stream)
|
|
369
|
+
hls.attachMedia(video.value)
|
|
303
370
|
|
|
304
371
|
if (video.value) {
|
|
305
372
|
hls.attachMedia(video.value)
|
|
@@ -365,6 +432,8 @@ function changeSpeed(e) {
|
|
|
365
432
|
video.value.playbackRate = video.value.playbackRate - 0.25
|
|
366
433
|
}
|
|
367
434
|
}
|
|
435
|
+
defineExpose({ startFullscreen });
|
|
436
|
+
|
|
368
437
|
</script>
|
|
369
438
|
<style>
|
|
370
439
|
video::cue {
|
|
@@ -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>
|