@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
- 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"
@@ -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', 'video-fullscreen-action'])
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 hls = new Hls()
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
- enterFullscreen(event)
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, (v) => {
255
- prepareVideoPlayer();
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
- isFullscreen.value = !!document.fullscreenElement
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
- function enterFullscreen(event) {
290
- emit('video-fullscreen-action', event)
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', '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.20",
4
+ "version": "1.1.1",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"