@grfzhl/vue-hls-player 1.1.2 → 1.1.4

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.
@@ -58,6 +58,7 @@
58
58
  </div>
59
59
  <slot name="before-transcripts"></slot>
60
60
  <SubtitleBlock
61
+ ref="transcriptRef"
61
62
  :subtitle="currentSubtitle"
62
63
  :cursor="videoCursor"
63
64
  :showTranscriptBlock="showTranscriptBlock"
@@ -144,6 +145,7 @@ const orientation = ref(null)
144
145
  const autoHideIntroTitle = ref(false);
145
146
  const initialPlayButton = ref(false);
146
147
  const hideInitialPlayButton = ref(false)
148
+ const transcriptRef = ref(null)
147
149
  const link = toRef(props, 'link');
148
150
  const previewImageLink = toRef(props, 'previewImageLink');
149
151
  let currentTime = 0
@@ -153,69 +155,6 @@ const videoElement = defineModel()
153
155
 
154
156
  onMounted(() => {
155
157
  prepareVideoPlayer()
156
- if (video.value) {
157
-
158
- // pass video element as reference to model
159
- if (!videoElement.value) {
160
- videoElement.value = video.value;
161
- }
162
-
163
- video.value.addEventListener('timeupdate', updateCurrentTime);
164
- document.addEventListener('fullscreenchange', onFullscreenChange);
165
- document.addEventListener('orientationchange', onOrientationChange);
166
- window.screen.orientation.addEventListener("change", onOrientationChange);
167
-
168
- if(video.value.paused || video.value.currentTime === 0) {
169
- initialPlayButton.value = true
170
-
171
- if(props.hideInitialPlayButton) {
172
- setTimeout(() => {
173
- hideInitialPlayButton.value = true
174
- }, 1200)
175
- }
176
- }
177
-
178
- /**
179
- * detect initial display orientation
180
- */
181
- if (typeof window.orientation === "undefined") {
182
- orientation.value = window.screen.orientation.angle === 0 || window.screen.orientation.angle === 180
183
- ? "portrait"
184
- : "landscape";
185
- } else {
186
- orientation.value = window.orientation === 0 || window.orientation === 180
187
- ? "portrait"
188
- : "landscape"; // for safari
189
- }
190
-
191
- /**
192
- * overwrite player.style video fullscreen button
193
- * to inject own fullscreen logic
194
- */
195
- const observer = new MutationObserver((mutationsList, observer) => {
196
- const mediaTheme = document.querySelector('.video-player-theme-container');
197
-
198
- if (mediaTheme && mediaTheme.shadowRoot) {
199
- const fullscreenButton = mediaTheme.shadowRoot.querySelector('media-fullscreen-button');
200
- const playbackRateButton = mediaTheme.shadowRoot.querySelector('media-playback-rate-menu');
201
- playbackRateButton.setAttribute('rates', '0.25 0.5 0.75 1 1.5 2 3');
202
- if (fullscreenButton) {
203
- fullscreenButton.handleClick = async (event) => {
204
- event.preventDefault();
205
- event.stopPropagation();
206
- event.stopImmediatePropagation();
207
- startFullscreen();
208
- }
209
- observer.disconnect();
210
- } else {
211
- console.error('Button not found in Shadow DOM!');
212
- }
213
- } else {
214
- console.error('Shadow Root not found!');
215
- }
216
- })
217
- observer.observe(document.body, { childList: true, subtree: true });
218
- }
219
158
  })
220
159
 
221
160
  onUpdated(() => {
@@ -352,6 +291,11 @@ function updateCurrentTime() {
352
291
  if(!video.value.paused) {
353
292
  initialPlayButton.value = false;
354
293
  }
294
+
295
+ // update transcripts
296
+ if(transcriptRef && video) {
297
+ transcriptRef.value.onTimeUpdate(video.value)
298
+ }
355
299
  }
356
300
 
357
301
  function toggleTranscript() {
@@ -373,7 +317,6 @@ function prepareVideoPlayer() {
373
317
  hls.loadSource(stream)
374
318
  hls.attachMedia(video.value)
375
319
 
376
- hls.attachMedia(video.value)
377
320
  video.value.muted = props.isMuted
378
321
  video.value.currentTime = props.progress
379
322
 
@@ -415,6 +358,73 @@ function prepareVideoPlayer() {
415
358
  });
416
359
  }
417
360
  setInterval(checkTrackModeChanges, 100);
361
+ initVideo();
362
+ }
363
+ }
364
+
365
+ function initVideo() {
366
+ if (video.value) {
367
+
368
+ // pass video element as reference to model
369
+ if (!videoElement.value) {
370
+ videoElement.value = video.value;
371
+ }
372
+
373
+ video.value.addEventListener('timeupdate', updateCurrentTime);
374
+ document.addEventListener('fullscreenchange', onFullscreenChange);
375
+ document.addEventListener('orientationchange', onOrientationChange);
376
+ window.screen.orientation.addEventListener("change", onOrientationChange);
377
+
378
+ if(video.value.paused || video.value.currentTime === 0) {
379
+ initialPlayButton.value = true
380
+
381
+ if(props.hideInitialPlayButton) {
382
+ setTimeout(() => {
383
+ hideInitialPlayButton.value = true
384
+ }, 1200)
385
+ }
386
+ }
387
+
388
+ /**
389
+ * detect initial display orientation
390
+ */
391
+ if (typeof window.orientation === "undefined") {
392
+ orientation.value = window.screen.orientation.angle === 0 || window.screen.orientation.angle === 180
393
+ ? "portrait"
394
+ : "landscape";
395
+ } else {
396
+ orientation.value = window.orientation === 0 || window.orientation === 180
397
+ ? "portrait"
398
+ : "landscape"; // for safari
399
+ }
400
+
401
+ /**
402
+ * overwrite player.style video fullscreen button
403
+ * to inject own fullscreen logic
404
+ */
405
+ const observer = new MutationObserver((mutationsList, observer) => {
406
+ const mediaTheme = document.querySelector('.video-player-theme-container');
407
+
408
+ if (mediaTheme && mediaTheme.shadowRoot) {
409
+ const fullscreenButton = mediaTheme.shadowRoot.querySelector('media-fullscreen-button');
410
+ const playbackRateButton = mediaTheme.shadowRoot.querySelector('media-playback-rate-menu');
411
+ playbackRateButton.setAttribute('rates', '0.25 0.5 0.75 1 1.5 2 3');
412
+ if (fullscreenButton) {
413
+ fullscreenButton.handleClick = async (event) => {
414
+ event.preventDefault();
415
+ event.stopPropagation();
416
+ event.stopImmediatePropagation();
417
+ startFullscreen();
418
+ }
419
+ observer.disconnect();
420
+ } else {
421
+ console.error('Button not found in Shadow DOM!');
422
+ }
423
+ } else {
424
+ console.error('Shadow Root not found!');
425
+ }
426
+ })
427
+ observer.observe(document.body, { childList: true, subtree: true });
418
428
  }
419
429
  }
420
430
 
@@ -143,7 +143,6 @@ const loadCues = async () => {
143
143
  if (props.subtitle) {
144
144
  const vttPath = props.subtitle.link;
145
145
  const txtPath = vttPath.replace(/\.vtt$/, '.txt');
146
-
147
146
  vttCues.value = await parseVTT(vttPath);
148
147
  txtCues.value = await parseTXT(txtPath);
149
148
  }
@@ -158,14 +157,14 @@ watch(
158
157
  }
159
158
  );
160
159
 
161
- watch(
162
- () => props.cursor,
163
- (currentTime) => {
164
- console.log("cursor watch", currentTime)
160
+ const onTimeUpdate = (video) => {
161
+ if (video) {
162
+ const currentTime = video.currentTime;
163
+ props.cursor = currentTime;
165
164
  highlightActiveCue(currentTime);
166
- checkCurrentCue(currentTime)
165
+ checkCurrentCue(currentTime);
167
166
  }
168
- );
167
+ };
169
168
 
170
169
  /**
171
170
  * highlgiht the current transcript part
@@ -223,7 +222,6 @@ function isWordActive(txtCue, word, wordIndex, txtIndex) {
223
222
 
224
223
  function checkCurrentCue(currentCursor) {
225
224
  Array.from(vttCues.value).forEach((a, index) => {
226
- console.log("current cue", a)
227
225
  if(currentCursor >= a.start && currentCursor <= a.end) {
228
226
  currentCue.value = a.text
229
227
  }
@@ -322,4 +320,6 @@ function secondsToTime(seconds) {
322
320
  const pad = (num) => String(num).padStart(2, '0');
323
321
  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
324
322
  }
323
+
324
+ defineExpose({ onTimeUpdate });
325
325
  </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.1.2",
4
+ "version": "1.1.4",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"