@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 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
- 1. Event, handling the fullscreen action of the player
128
- @video-fullscreen-action="fullScreenAction"
129
- ```
130
- const fullScreenAction = (data) => {
131
- if(isFullscreen.value) {
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', 'video-fullscreen-action'])
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
- enterFullscreen(event)
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
- function onFullscreenChange() {
253
- isFullscreen.value = !!document.fullscreenElement
254
- emit('video-fullscreen-change', document.fullscreenElement)
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
- function enterFullscreen(event) {
280
- emit('video-fullscreen-action', event)
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', 'video-fullscreen-action'])
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 oVideoFullscreenAction(data) {
95
- emit('video-fullscreen-action', data)
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 oVideoFullscreenAction(data) {
101
- emit('video-fullscreen-action', data)
107
+ function startFullscreen() {
108
+ childRef.value.startFullscreen();
102
109
  }
103
110
  </script>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@grfzhl/vue-hls-player",
3
3
  "private": false,
4
- "version": "1.0.19",
4
+ "version": "1.1.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"