@grfzhl/vue-hls-player 1.1.4 → 1.1.6
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.
|
@@ -144,21 +144,17 @@ const isFullscreen = ref(false);
|
|
|
144
144
|
const orientation = ref(null)
|
|
145
145
|
const autoHideIntroTitle = ref(false);
|
|
146
146
|
const initialPlayButton = ref(false);
|
|
147
|
-
const hideInitialPlayButton = ref(false)
|
|
148
|
-
const transcriptRef = ref(null)
|
|
149
|
-
const link = toRef(props, 'link');
|
|
147
|
+
const hideInitialPlayButton = ref(false);
|
|
148
|
+
const transcriptRef = ref(null);
|
|
150
149
|
const previewImageLink = toRef(props, 'previewImageLink');
|
|
150
|
+
const link = toRef(props, 'link');
|
|
151
151
|
let currentTime = 0
|
|
152
152
|
let hls = null
|
|
153
153
|
|
|
154
154
|
const videoElement = defineModel()
|
|
155
155
|
|
|
156
156
|
onMounted(() => {
|
|
157
|
-
prepareVideoPlayer()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
onUpdated(() => {
|
|
161
|
-
|
|
157
|
+
prepareVideoPlayer(props.link)
|
|
162
158
|
})
|
|
163
159
|
|
|
164
160
|
onUnmounted(() => {
|
|
@@ -178,7 +174,11 @@ const mutedAttr = computed(() => {
|
|
|
178
174
|
const currentSubtitle = computed(() => {
|
|
179
175
|
if(props.subtitles) {
|
|
180
176
|
const current = props.subtitles.filter((subt) => {
|
|
181
|
-
|
|
177
|
+
if(currentSubtitleLang.value) {
|
|
178
|
+
return subt.lang === currentSubtitleLang.value
|
|
179
|
+
} else {
|
|
180
|
+
return subt.lang === "en"
|
|
181
|
+
}
|
|
182
182
|
})
|
|
183
183
|
return current.length ? current[0] : null
|
|
184
184
|
}
|
|
@@ -195,10 +195,11 @@ watch([props, videoElement], (a) => {
|
|
|
195
195
|
}
|
|
196
196
|
})
|
|
197
197
|
|
|
198
|
-
watch(
|
|
198
|
+
watch(
|
|
199
|
+
() => props.link,
|
|
200
|
+
(newLink, oldLink) => {
|
|
199
201
|
if (newLink !== oldLink) {
|
|
200
|
-
|
|
201
|
-
prepareVideoPlayer();
|
|
202
|
+
prepareVideoPlayer(newLink);
|
|
202
203
|
}
|
|
203
204
|
})
|
|
204
205
|
|
|
@@ -307,15 +308,18 @@ function seekVideo(time) {
|
|
|
307
308
|
video.value.play()
|
|
308
309
|
}
|
|
309
310
|
|
|
310
|
-
function prepareVideoPlayer() {
|
|
311
|
+
function prepareVideoPlayer(link) {
|
|
312
|
+
let initiallyLoaded = true;
|
|
311
313
|
if (video.value) {
|
|
312
314
|
if (hls) {
|
|
315
|
+
hls.detachMedia();
|
|
313
316
|
hls.destroy();
|
|
317
|
+
initiallyLoaded = false;
|
|
314
318
|
}
|
|
315
319
|
hls = new Hls();
|
|
316
|
-
|
|
317
|
-
hls.loadSource(stream)
|
|
320
|
+
hls.loadSource(link)
|
|
318
321
|
hls.attachMedia(video.value)
|
|
322
|
+
hls.recoverMediaError()
|
|
319
323
|
|
|
320
324
|
video.value.muted = props.isMuted
|
|
321
325
|
video.value.currentTime = props.progress
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<span
|
|
29
29
|
v-for="(word, wordIndex) in txtCue.dialog[0].text.split('')"
|
|
30
30
|
:key="wordIndex"
|
|
31
|
-
:class="{ 'active-word': isWordActive(txtCue, word, wordIndex, index) && isTxtCueActive(txtCue) }"
|
|
31
|
+
:class="{ 'active-word': isWordActive(txtCue, word, wordIndex, index, currentCue) && isTxtCueActive(txtCue) }"
|
|
32
32
|
>
|
|
33
33
|
{{ word }}
|
|
34
34
|
</span>
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
</style>
|
|
112
112
|
|
|
113
113
|
<script setup>
|
|
114
|
-
import { onMounted, watch, ref } from 'vue';
|
|
114
|
+
import { onMounted, watch, ref, nextTick } from 'vue';
|
|
115
115
|
|
|
116
116
|
const props = defineProps({
|
|
117
117
|
subtitle: {
|
|
@@ -137,6 +137,7 @@ const subtitlesContainer = ref(null);
|
|
|
137
137
|
const vttCues = ref([]);
|
|
138
138
|
const txtCues = ref([]);
|
|
139
139
|
const currentCue = ref(null);
|
|
140
|
+
const videoCursor = ref(0);
|
|
140
141
|
|
|
141
142
|
|
|
142
143
|
const loadCues = async () => {
|
|
@@ -158,8 +159,9 @@ watch(
|
|
|
158
159
|
);
|
|
159
160
|
|
|
160
161
|
const onTimeUpdate = (video) => {
|
|
161
|
-
if (video) {
|
|
162
|
+
if (video && txtCues?.value?.length && vttCues?.value?.length) {
|
|
162
163
|
const currentTime = video.currentTime;
|
|
164
|
+
videoCursor.value = currentTime;
|
|
163
165
|
props.cursor = currentTime;
|
|
164
166
|
highlightActiveCue(currentTime);
|
|
165
167
|
checkCurrentCue(currentTime);
|
|
@@ -195,7 +197,7 @@ function seekTo(time) {
|
|
|
195
197
|
* @param txtCue
|
|
196
198
|
*/
|
|
197
199
|
function isTxtCueActive(txtCue) {
|
|
198
|
-
return
|
|
200
|
+
return videoCursor.value >= txtCue.start && videoCursor.value <= txtCue.end;
|
|
199
201
|
}
|
|
200
202
|
|
|
201
203
|
/**
|
|
@@ -206,24 +208,23 @@ function isTxtCueActive(txtCue) {
|
|
|
206
208
|
* @param wordIndex
|
|
207
209
|
* @param txtIndex
|
|
208
210
|
*/
|
|
209
|
-
function isWordActive(txtCue, word, wordIndex, txtIndex) {
|
|
210
|
-
|
|
211
|
-
if(!currentCue.value || !word || !txtCue) {
|
|
211
|
+
function isWordActive(txtCue, word, wordIndex, txtIndex, currentCue) {
|
|
212
|
+
if(!currentCue || !word || !txtCue) {
|
|
212
213
|
return false
|
|
213
214
|
}
|
|
214
|
-
const startPos = txtCue.dialog[0].text.indexOf(currentCue
|
|
215
|
-
const endPos = startPos + currentCue.
|
|
216
|
-
console.log("can word marked", startPos, endPos, wordIndex)
|
|
215
|
+
const startPos = txtCue.dialog[0].text.indexOf(currentCue)
|
|
216
|
+
const endPos = startPos + currentCue.length
|
|
217
217
|
if(wordIndex >= startPos && wordIndex < endPos) {
|
|
218
218
|
return true;
|
|
219
219
|
}
|
|
220
220
|
return false;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
function checkCurrentCue(currentCursor) {
|
|
224
|
-
Array.from(vttCues.value).forEach((a, index) => {
|
|
225
|
-
if(
|
|
223
|
+
async function checkCurrentCue(currentCursor) {
|
|
224
|
+
Array.from(vttCues.value).forEach(async (a, index) => {
|
|
225
|
+
if(videoCursor.value >= a.start && videoCursor.value <= a.end) {
|
|
226
226
|
currentCue.value = a.text
|
|
227
|
+
await nextTick()
|
|
227
228
|
}
|
|
228
229
|
});
|
|
229
230
|
}
|
|
@@ -237,7 +238,7 @@ async function parseVTT(fileUrl) {
|
|
|
237
238
|
const response = await fetch(fileUrl);
|
|
238
239
|
const text = await response.text();
|
|
239
240
|
const cues = [];
|
|
240
|
-
const lines = text.split('\n');
|
|
241
|
+
const lines = text.replace(/\r/g, '').split('\n');
|
|
241
242
|
let cue = null;
|
|
242
243
|
|
|
243
244
|
for (let i = 0; i < lines.length; i++) {
|