@grfzhl/vue-hls-player 1.0.7 → 1.0.9

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
@@ -172,7 +172,25 @@ example:
172
172
  }]
173
173
  ```
174
174
 
175
+ **isMuted**:
176
+ 1 value: true or false, type: Boolean
177
+
178
+ it makes the video muted
179
+
180
+ **autoplay**:
181
+ 1. value: true or false, type Boolean
182
+
183
+ it will set the native <video> autoplay property
184
+
175
185
  ### Last release:
186
+ v1.0.9
187
+ - Fix sizes in fullscreen mode for video
188
+ - Hide transcript block completely when hidden
189
+
190
+ v1.0.8
191
+ - Add slots to inject own elements nearby video element
192
+ - Add prop for autoplay video
193
+
176
194
  v1.0.7
177
195
  - Add function to handle own logic for fullscreen
178
196
 
@@ -1,38 +1,45 @@
1
1
  <template>
2
2
  <div class="video-container">
3
- <media-theme-sutro class="video-player-theme-container">
4
- <video
5
- class="hls-player"
6
- slot="media"
7
- @pause="pause"
8
- @keyup="changeSpeed"
9
- @ended="onVideoEnd"
10
- @seek="seekVideo"
11
- ref="video"
12
- :poster="previewImageLink"
13
- :controls="false"
14
- :title="title"
15
- controlslist="nodownload"
16
- playsinline
17
- crossorigin
18
- >
19
- <source
20
- :src="link"
21
- type="application/x-mpegURL"
22
- />
23
- <track
24
- v-if="subtitles.length"
25
- v-for="(subtitle, i) in subtitles"
26
- :src="subtitle.link"
27
- kind="subtitles"
28
- :srclang="subtitle.lang"
29
- :label="subtitle.label" :default="i === 0" />
30
- </video>
31
- </media-theme-sutro>
32
- <div class="custom-subtitles" v-show="!showTranscriptBlock">
33
- <div class="subtitle-text" ref="subtitlesContainer" style="display: none;"></div>
3
+ <div class="media-container" id="hls-player-media-container">
4
+ <slot name="before-media"></slot>
5
+ <media-theme-sutro class="video-player-theme-container" :class="{'is-fullscreen': isFullscreen}">
6
+ <video
7
+ class="hls-player"
8
+ slot="media"
9
+ @pause="pause"
10
+ @keyup="changeSpeed"
11
+ @ended="onVideoEnd"
12
+ @seek="seekVideo"
13
+ ref="video"
14
+ :poster="previewImageLink"
15
+ :controls="false"
16
+ :title="title"
17
+ controlslist="nodownload"
18
+ playsinline
19
+ crossorigin
20
+ :muted="mutedAttr"
21
+ :autoplay="autoplay && isMuted"
22
+ >
23
+ <source
24
+ :src="link"
25
+ type="application/x-mpegURL"
26
+ />
27
+ <track
28
+ v-if="subtitles.length"
29
+ v-for="(subtitle, i) in subtitles"
30
+ :src="subtitle.link"
31
+ kind="subtitles"
32
+ :srclang="subtitle.lang"
33
+ :label="subtitle.label" :default="i === 0" />
34
+ </video>
35
+ </media-theme-sutro>
36
+ <div class="custom-subtitles" v-show="(isFullscreen) || (!showTranscriptBlock)">
37
+ <div class="subtitle-text" ref="subtitlesContainer" style="display: none;"></div>
38
+ </div>
39
+ <slot name="after-media"></slot>
34
40
  </div>
35
41
  </div>
42
+ <slot name="before-transcripts"></slot>
36
43
  <SubtitleBlock
37
44
  :subtitle="currentSubtitle"
38
45
  :cursor="videoCursor"
@@ -40,10 +47,12 @@
40
47
  @seek="seekVideo"
41
48
  @toggleTranscript="toggleTranscript">
42
49
  </SubtitleBlock>
50
+ <slot name="after-transcripts"></slot>
51
+ <slot name="default"></slot>
43
52
  </template>
44
53
 
45
54
  <script setup>
46
- import { onMounted, onUpdated, ref, onUnmounted, computed } from 'vue'
55
+ import { onMounted, onUpdated, ref, onUnmounted, computed, watch } from 'vue'
47
56
  import Hls from 'hls.js'
48
57
  import 'player.style/sutro';
49
58
  import SubtitleBlock from './SubtitleBlock.vue';
@@ -69,6 +78,10 @@ const props = defineProps({
69
78
  type: Boolean,
70
79
  default: false
71
80
  },
81
+ autoplay: {
82
+ type: Boolean,
83
+ default: false
84
+ },
72
85
  /**
73
86
  * array of object, for
74
87
  * subtitles to append:
@@ -99,10 +112,17 @@ const currentSubtitleLang = ref(null)
99
112
  const videoCursor = ref(0)
100
113
  const isFullscreen = ref(false);
101
114
 
115
+ const videoElement = defineModel()
116
+
102
117
  onMounted(() => {
103
118
  prepareVideoPlayer()
104
119
  if (video.value) {
105
- checkFullscreen();
120
+
121
+ // pass video element as reference to model
122
+ if (!videoElement.value) {
123
+ videoElement.value = video.value;
124
+ }
125
+
106
126
  video.value.addEventListener('timeupdate', updateCurrentTime);
107
127
  document.addEventListener('fullscreenchange', onFullscreenChange);
108
128
 
@@ -135,6 +155,7 @@ onMounted(() => {
135
155
  })
136
156
 
137
157
  onUpdated(() => {
158
+
138
159
  })
139
160
 
140
161
  onUnmounted(() => {
@@ -144,6 +165,11 @@ onUnmounted(() => {
144
165
  }
145
166
  });
146
167
 
168
+ const mutedAttr = computed(() => {
169
+ // autoplay is only possible when muted
170
+ return (props.autoplay || props.isMuted);
171
+ })
172
+
147
173
  const currentSubtitle = computed(() => {
148
174
  if(props.subtitles) {
149
175
  const current = props.subtitles.filter((subt) => {
@@ -154,12 +180,18 @@ const currentSubtitle = computed(() => {
154
180
  return null
155
181
  })
156
182
 
157
- function checkFullscreen() {
158
- isFullscreen.value = !!document.fullscreenElement;
159
- };
183
+ watch([props, videoElement], (a) => {
184
+ if(a[0].autoplay && a[1]) {
185
+ // autoplay is only possible when muted
186
+ a[1].muted = true
187
+ setTimeout(() => {
188
+ a[1].play();
189
+ }, 200)
190
+ }
191
+ })
160
192
 
161
193
  function onFullscreenChange() {
162
- checkFullscreen();
194
+ isFullscreen.value = !!document.fullscreenElement
163
195
  emit('video-fullscreen-change', document.fullscreenElement)
164
196
  };
165
197
 
@@ -194,25 +226,31 @@ function prepareVideoPlayer() {
194
226
  track.addEventListener("cuechange", () => {
195
227
  const activeCues = track.activeCues;
196
228
  currentSubtitleLang.value = track.language
197
- if (activeCues && activeCues.length > 0) {
198
- subtitlesContainer.value.textContent = activeCues[0].text
199
- subtitlesContainer.value.style.display = "block";
200
- } else {
201
- subtitlesContainer.value.style.display = "none";
229
+ if(subtitlesContainer.value) {
230
+ if (activeCues && activeCues.length > 0) {
231
+ subtitlesContainer.value.textContent = activeCues[0].text
232
+ subtitlesContainer.value.style.display = "block";
233
+ } else {
234
+ subtitlesContainer.value.style.display = "none";
235
+ }
202
236
  }
203
237
  });
204
238
  if (track.mode !== previousModes[index]) {
205
239
  if (track.mode === "showing") {
206
240
  const activeCues = track.activeCues;
207
241
  currentSubtitleLang.value = track.language
208
- if (activeCues && activeCues.length > 0) {
209
- subtitlesContainer.value.style.display = "block";
210
- subtitlesContainer.value.textContent = activeCues[0].text
211
- } else {
212
- subtitlesContainer.value.style.display = "none";
242
+ if(subtitlesContainer.value) {
243
+ if (activeCues && activeCues.length > 0) {
244
+ subtitlesContainer.value.style.display = "block";
245
+ subtitlesContainer.value.textContent = activeCues[0].text
246
+ } else {
247
+ subtitlesContainer.value.style.display = "none";
248
+ }
213
249
  }
214
250
  } else {
215
- subtitlesContainer.value.style.display = "none";
251
+ if(subtitlesContainer.value) {
252
+ subtitlesContainer.value.style.display = "none";
253
+ }
216
254
  }
217
255
  previousModes[index] = track.mode;
218
256
  }
@@ -270,9 +308,22 @@ function changeSpeed(e) {
270
308
 
271
309
  .video-player-theme-container, .hls-player {
272
310
  width: 100%;
311
+ height: 100%;
273
312
  }
274
313
 
275
314
  .video-container {
276
315
  position: relative;
316
+ line-height: 0;
317
+ }
318
+
319
+ .video-player-theme-container.is-fullscreen {
320
+ width: 100vw;
321
+ height: 100vh;
322
+ object-fit: cover;
277
323
  }
324
+ .video-player-theme-container.is-fullscreen .hls-player {
325
+ width: 100vw;
326
+ height: 100vh;
327
+ object-fit: cover;
328
+ }
278
329
  </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="transcript-container" ref="subtitlesContainer">
2
+ <div class="transcript-container" ref="subtitlesContainer" v-if="showTranscriptBlock">
3
3
  <div class="transcript-toggle">
4
4
  <button data-headlessui-state="open" @click="toggleTranscript()">
5
5
  <div class="icon">
@@ -4,6 +4,7 @@
4
4
  :link="link"
5
5
  :progress="progress"
6
6
  :isMuted="isMuted"
7
+ :autoplay="autoplay"
7
8
  :isControls="isControls"
8
9
  :onVideoEnd="onVideoEnd"
9
10
  :isFullscreen="isFullscreen"
@@ -12,14 +13,23 @@
12
13
  @video-ended="onVideoEnd"
13
14
  @video-fullscreen-change="onFullscreenChange"
14
15
  @video-fullscreen-action="oVideoFullscreenAction"
15
- />
16
+ v-model="videoElement"
17
+ >
18
+ <template v-slot:before-media><slot name="before-media"></slot></template>
19
+ <template v-slot:after-media><slot name="after-media"></slot></template>
20
+ <template v-slot:before-transcripts><slot name="before-transcripts"></slot></template>
21
+ <template v-slot:after-transcripts><slot name="after-transcripts"></slot></template>
22
+ </BasePlayer>
16
23
  </template>
17
24
 
18
25
  <script setup>
19
26
  import BasePlayer from './BasePlayer.vue'
27
+ import { ref } from 'vue'
20
28
 
21
29
  const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change'])
22
30
 
31
+ const videoElement = ref(null);
32
+
23
33
  defineProps({
24
34
  previewImageLink: {
25
35
  type: String,
@@ -37,6 +47,10 @@ defineProps({
37
47
  type: Boolean,
38
48
  default: false
39
49
  },
50
+ autoplay: {
51
+ type: Boolean,
52
+ default: false
53
+ },
40
54
  isControls: {
41
55
  type: Boolean,
42
56
  default: true
@@ -11,8 +11,15 @@
11
11
  :link="link"
12
12
  :progress="progress"
13
13
  :isMuted="isMuted"
14
- />
15
-
14
+ :autoplay="autoplay"
15
+ v-model="videoElement"
16
+ >
17
+ <template v-slot:before-media><slot name="before-media"></slot></template>
18
+ <template v-slot:after-media><slot name="after-media"></slot></template>
19
+ <template v-slot:before-transcripts><slot name="before-transcripts"></slot></template>
20
+ <template v-slot:after-transcripts><slot name="after-transcripts"></slot></template>
21
+ </VDefaultVideoPlayer>
22
+
16
23
  <VPreviewVideoPlayer
17
24
  v-else-if="type === 'preview'"
18
25
  :previewImageLink="previewImageLink"
@@ -23,9 +30,12 @@
23
30
  <script setup>
24
31
  import VDefaultVideoPlayer from './VDefaultVideoPlayer.vue'
25
32
  import VPreviewVideoPlayer from './VPreviewVideoPlayer.vue'
33
+ import { ref } from 'vue'
26
34
 
27
35
  const emit = defineEmits(['pause', 'video-ended', 'video-fullscreen-change', 'video-fullscreen-action'])
28
36
 
37
+ const videoElement = ref(null);
38
+
29
39
  defineProps({
30
40
  previewImageLink: {
31
41
  type: String,
@@ -47,6 +57,10 @@ defineProps({
47
57
  type: Boolean,
48
58
  default: false
49
59
  },
60
+ autoplay: {
61
+ type: Boolean,
62
+ default: false
63
+ },
50
64
  isControls: {
51
65
  type: Boolean,
52
66
  default: true
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.7",
4
+ "version": "1.0.9",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"