@mindedge/vuetify-player 0.3.0 → 0.4.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 +88 -50
- package/package.json +1 -1
- package/src/components/Media/CaptionsMenu.vue +260 -94
- package/src/components/Media/Html5Player.vue +595 -349
- package/src/components/Media/PlaylistMenu.vue +40 -42
- package/src/components/Media/SettingsMenu.vue +98 -0
- package/src/components/Media/YoutubePlayer.vue +5 -1
- package/src/components/VuetifyPlayer.vue +214 -28
- package/src/i18n/en-US.js +10 -0
- package/src/i18n/es-ES.js +16 -3
- package/src/i18n/i18n.js +6 -1
- package/src/i18n/sv-SE.js +12 -0
|
@@ -1,71 +1,153 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-card>
|
|
3
|
-
<v-card-actions class="
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
<v-card v-if="visibleState">
|
|
3
|
+
<v-card-actions class="d-flex flex-wrap flex-row-reverse mb-0 pb-0">
|
|
4
|
+
<div class="d-flex ml-auto">
|
|
5
|
+
<v-tooltip v-if="!hideAutoscroll" top>
|
|
6
|
+
<template #activator="{ on, attrs }">
|
|
7
|
+
<div v-bind="attrs" v-on="on">
|
|
8
|
+
<v-switch
|
|
9
|
+
:input-value="autoscrollState"
|
|
10
|
+
color="primary"
|
|
11
|
+
text
|
|
12
|
+
class="d-flex align-self-center"
|
|
13
|
+
@click="onClickToggleAutoscroll"
|
|
14
|
+
>
|
|
15
|
+
<template #label>
|
|
16
|
+
<div v-if="autoscrollState">
|
|
17
|
+
<v-icon> mdi-lock-open-variant </v-icon>
|
|
18
|
+
<span class="sr-only">
|
|
19
|
+
{{
|
|
20
|
+
t(
|
|
21
|
+
language,
|
|
22
|
+
'captions.autoscroll_enabled'
|
|
23
|
+
)
|
|
24
|
+
}}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
<div v-else>
|
|
28
|
+
<v-icon>mdi-arrow-vertical-lock</v-icon>
|
|
29
|
+
<span class="sr-only">
|
|
30
|
+
{{
|
|
31
|
+
t(
|
|
32
|
+
language,
|
|
33
|
+
'captions.autoscroll_disabled'
|
|
34
|
+
)
|
|
35
|
+
}}
|
|
36
|
+
</span>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
</v-switch>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
<span>{{
|
|
43
|
+
autoscrollState
|
|
44
|
+
? t(language, 'captions.disable_autoscroll')
|
|
45
|
+
: t(language, 'captions.enable_autoscroll')
|
|
46
|
+
}}</span>
|
|
47
|
+
</v-tooltip>
|
|
48
|
+
|
|
49
|
+
<v-tooltip v-if="!hideParagraphView" top>
|
|
50
|
+
<template #activator="{ on, attrs }">
|
|
51
|
+
<v-btn
|
|
52
|
+
color="primary"
|
|
53
|
+
text
|
|
54
|
+
class="d-flex align-self-center"
|
|
55
|
+
v-bind="attrs"
|
|
56
|
+
v-on="on"
|
|
57
|
+
@click="onClickToggleParagraphView"
|
|
58
|
+
>
|
|
59
|
+
<v-icon>{{
|
|
60
|
+
paragraphViewState
|
|
61
|
+
? 'mdi-closed-caption-outline'
|
|
62
|
+
: 'mdi-text-box-outline'
|
|
63
|
+
}}</v-icon>
|
|
64
|
+
<span class="sr-only">{{
|
|
65
|
+
paragraphViewState
|
|
66
|
+
? t(language, 'captions.view_as_captions')
|
|
67
|
+
: t(language, 'captions.view_as_paragraph')
|
|
68
|
+
}}</span>
|
|
69
|
+
</v-btn></template
|
|
12
70
|
>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
71
|
+
<span>{{
|
|
72
|
+
paragraphViewState
|
|
73
|
+
? t(language, 'captions.view_as_captions')
|
|
74
|
+
: t(language, 'captions.view_as_paragraph')
|
|
75
|
+
}}</span>
|
|
76
|
+
</v-tooltip>
|
|
77
|
+
|
|
78
|
+
<v-tooltip v-if="!hideExpand" top>
|
|
79
|
+
<template #activator="{ on, attrs }">
|
|
80
|
+
<v-btn
|
|
81
|
+
color="primary"
|
|
82
|
+
text
|
|
83
|
+
class="d-flex align-self-center"
|
|
84
|
+
v-bind="attrs"
|
|
85
|
+
v-on="on"
|
|
86
|
+
@click="onClickToggleExpand"
|
|
87
|
+
>
|
|
88
|
+
<v-icon>{{
|
|
89
|
+
expandedState
|
|
90
|
+
? 'mdi-arrow-collapse'
|
|
91
|
+
: 'mdi-arrow-expand'
|
|
92
|
+
}}</v-icon>
|
|
93
|
+
<span class="sr-only">{{
|
|
94
|
+
expandedState
|
|
95
|
+
? t(language, 'captions.collapse')
|
|
96
|
+
: t(language, 'captions.expand')
|
|
97
|
+
}}</span>
|
|
98
|
+
</v-btn></template
|
|
99
|
+
>
|
|
100
|
+
<span>{{
|
|
101
|
+
expandedState
|
|
102
|
+
? t(language, 'captions.collapse')
|
|
103
|
+
: t(language, 'captions.expand')
|
|
104
|
+
}}</span>
|
|
105
|
+
</v-tooltip>
|
|
106
|
+
|
|
107
|
+
<v-tooltip v-if="!hideClose" top>
|
|
108
|
+
<template #activator="{ on, attrs }">
|
|
109
|
+
<v-btn
|
|
110
|
+
color="primary"
|
|
111
|
+
text
|
|
112
|
+
class="d-flex align-self-center"
|
|
113
|
+
v-bind="attrs"
|
|
114
|
+
v-on="on"
|
|
115
|
+
@click="onClickClose"
|
|
116
|
+
>
|
|
117
|
+
<v-icon>mdi-close</v-icon>
|
|
118
|
+
</v-btn></template
|
|
39
119
|
>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
120
|
+
<span>{{ t(language, 'captions.close') }}</span>
|
|
121
|
+
</v-tooltip>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="d-flex flex-grow-1">
|
|
125
|
+
<v-text-field
|
|
126
|
+
id="captions-search"
|
|
127
|
+
v-model="search"
|
|
128
|
+
:label="t(language, 'captions.search')"
|
|
129
|
+
append-icon="mdi-magnify"
|
|
130
|
+
class="ml-2 mr-12"
|
|
131
|
+
clearable
|
|
49
132
|
>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
? t(language, 'captions.collapse')
|
|
53
|
-
: t(language, 'captions.expand')
|
|
54
|
-
}}</span>
|
|
55
|
-
</v-tooltip>
|
|
133
|
+
</v-text-field>
|
|
134
|
+
</div>
|
|
56
135
|
</v-card-actions>
|
|
57
|
-
<v-card-text>
|
|
136
|
+
<v-card-text class="mt-0 pt-0">
|
|
137
|
+
<span v-if="search && !filteredCues.length" class="caption">
|
|
138
|
+
{{ t(language, 'captions.none_found', [search]) }}
|
|
139
|
+
</span>
|
|
58
140
|
<v-list ref="captionList" :class="captionsList">
|
|
59
141
|
<v-list-item-group v-model="captionIndex">
|
|
60
142
|
<v-list-item
|
|
61
143
|
ref="captionItems"
|
|
62
|
-
v-for="(cue, index) in
|
|
144
|
+
v-for="(cue, index) in filteredCues"
|
|
63
145
|
:key="index"
|
|
64
|
-
:two-line="
|
|
146
|
+
:two-line="expandedState"
|
|
65
147
|
@click="onCueClick(cue.startTime)"
|
|
66
148
|
>
|
|
67
|
-
<template v-if="!
|
|
68
|
-
<v-list-item-icon v-if="!
|
|
149
|
+
<template v-if="!expandedState">
|
|
150
|
+
<v-list-item-icon v-if="!paragraphViewState">
|
|
69
151
|
<v-icon
|
|
70
152
|
>{{
|
|
71
153
|
index === captionIndex
|
|
@@ -80,7 +162,7 @@
|
|
|
80
162
|
class="caption-text"
|
|
81
163
|
></v-list-item-title>
|
|
82
164
|
</v-list-item-content>
|
|
83
|
-
<v-list-item-action v-if="!
|
|
165
|
+
<v-list-item-action v-if="!paragraphViewState">
|
|
84
166
|
<span aria-hidden="true">
|
|
85
167
|
{{
|
|
86
168
|
filters.playerShortDuration(
|
|
@@ -94,13 +176,15 @@
|
|
|
94
176
|
</span>
|
|
95
177
|
</v-list-item-action>
|
|
96
178
|
</template>
|
|
97
|
-
<template v-if="
|
|
179
|
+
<template v-if="expandedState">
|
|
98
180
|
<v-list-item-content>
|
|
99
181
|
<v-list-item-title
|
|
100
182
|
v-html="cue.rawText || cue.text"
|
|
101
183
|
class="caption-text"
|
|
102
184
|
></v-list-item-title>
|
|
103
|
-
<v-list-item-subtitle
|
|
185
|
+
<v-list-item-subtitle
|
|
186
|
+
v-if="!paragraphViewState"
|
|
187
|
+
>
|
|
104
188
|
<v-icon
|
|
105
189
|
>{{
|
|
106
190
|
index === captionIndex
|
|
@@ -139,10 +223,42 @@ export default {
|
|
|
139
223
|
props: {
|
|
140
224
|
value: { type: [Object, Array], required: true },
|
|
141
225
|
language: { type: String, required: false, default: 'en-US' },
|
|
226
|
+
expanded: { type: Boolean, required: false, default: undefined },
|
|
227
|
+
hideExpand: { type: Boolean, required: false, default: true },
|
|
228
|
+
paragraphView: { type: Boolean, required: false, default: undefined },
|
|
229
|
+
hideParagraphView: { type: Boolean, required: false, default: false },
|
|
230
|
+
autoscroll: { type: Boolean, required: false, default: undefined },
|
|
231
|
+
hideAutoscroll: { type: Boolean, required: false, default: false },
|
|
232
|
+
visible: { type: Boolean, required: false, default: undefined },
|
|
233
|
+
hideClose: { type: Boolean, required: false, default: false },
|
|
142
234
|
},
|
|
235
|
+
emits: [
|
|
236
|
+
'click:cue',
|
|
237
|
+
'click:expand',
|
|
238
|
+
'click:paragraph',
|
|
239
|
+
'click:autoscroll',
|
|
240
|
+
'click:close',
|
|
241
|
+
'update:expanded',
|
|
242
|
+
'update:paragraph-view',
|
|
243
|
+
'update:autoscroll',
|
|
244
|
+
'update:visible',
|
|
245
|
+
],
|
|
143
246
|
computed: {
|
|
247
|
+
filteredCues() {
|
|
248
|
+
// Cues are an object with keys of 0,1,2,3...
|
|
249
|
+
const cues = Object.values(this.cues)
|
|
250
|
+
if (this.search !== '') {
|
|
251
|
+
return cues.filter((c) =>
|
|
252
|
+
c.text
|
|
253
|
+
.toLowerCase()
|
|
254
|
+
.includes((this.search || '').toLowerCase())
|
|
255
|
+
)
|
|
256
|
+
} else {
|
|
257
|
+
return cues
|
|
258
|
+
}
|
|
259
|
+
},
|
|
144
260
|
captionsList() {
|
|
145
|
-
return !this.
|
|
261
|
+
return !this.expandedState
|
|
146
262
|
? 'captions-list captions-list--state-collapsed'
|
|
147
263
|
: 'captions-list captions-list--state-expanded'
|
|
148
264
|
},
|
|
@@ -150,12 +266,12 @@ export default {
|
|
|
150
266
|
// Normal cues view
|
|
151
267
|
if (
|
|
152
268
|
typeof this.captions.cues !== 'undefined' &&
|
|
153
|
-
!this.
|
|
269
|
+
!this.paragraphViewState
|
|
154
270
|
) {
|
|
155
271
|
return this.captions.cues
|
|
156
272
|
} else if (
|
|
157
273
|
typeof this.captions.cues !== 'undefined' &&
|
|
158
|
-
this.
|
|
274
|
+
this.paragraphViewState
|
|
159
275
|
) {
|
|
160
276
|
// Paragraph view
|
|
161
277
|
let cues = this.captions.cues
|
|
@@ -215,15 +331,70 @@ export default {
|
|
|
215
331
|
return []
|
|
216
332
|
}
|
|
217
333
|
},
|
|
334
|
+
expandedState: {
|
|
335
|
+
get() {
|
|
336
|
+
if (typeof this.expanded !== 'undefined') {
|
|
337
|
+
return this.expanded
|
|
338
|
+
} else {
|
|
339
|
+
return this.localExpanded
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
set(v) {
|
|
343
|
+
this.localExpanded = v
|
|
344
|
+
this.$emit('update:expanded', v)
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
paragraphViewState: {
|
|
348
|
+
get() {
|
|
349
|
+
if (typeof this.paragraphView !== 'undefined') {
|
|
350
|
+
return this.paragraphView
|
|
351
|
+
} else {
|
|
352
|
+
return this.localParagraphView
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
set(v) {
|
|
356
|
+
this.$emit('update:paragraph-view', v)
|
|
357
|
+
this.localParagraphView = v
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
autoscrollState: {
|
|
361
|
+
get() {
|
|
362
|
+
if (typeof this.autoscroll !== 'undefined') {
|
|
363
|
+
return this.autoscroll
|
|
364
|
+
} else {
|
|
365
|
+
return this.localAutoscroll
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
set(v) {
|
|
369
|
+
this.$emit('update:autoscroll', v)
|
|
370
|
+
this.localAutoscroll = v
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
visibleState: {
|
|
374
|
+
get() {
|
|
375
|
+
if (typeof this.visible !== 'undefined') {
|
|
376
|
+
return this.visible
|
|
377
|
+
} else {
|
|
378
|
+
return this.localVisible
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
set(v) {
|
|
382
|
+
this.$emit('update:visible', v)
|
|
383
|
+
this.localVisible = v
|
|
384
|
+
},
|
|
385
|
+
},
|
|
218
386
|
},
|
|
219
387
|
data() {
|
|
220
388
|
return {
|
|
221
389
|
t,
|
|
222
390
|
filters,
|
|
391
|
+
search: '',
|
|
223
392
|
captions: {},
|
|
224
393
|
captionIndex: 0,
|
|
225
|
-
|
|
226
|
-
|
|
394
|
+
localExpanded: false,
|
|
395
|
+
localParagraphView: false,
|
|
396
|
+
localAutoscroll: true,
|
|
397
|
+
localVisible: true,
|
|
227
398
|
}
|
|
228
399
|
},
|
|
229
400
|
watch: {
|
|
@@ -235,6 +406,11 @@ export default {
|
|
|
235
406
|
},
|
|
236
407
|
},
|
|
237
408
|
},
|
|
409
|
+
|
|
410
|
+
mounted() {
|
|
411
|
+
this.captions = this.value
|
|
412
|
+
this.captionIndex = this.currentCue(this.captions)
|
|
413
|
+
},
|
|
238
414
|
methods: {
|
|
239
415
|
currentCue(captions) {
|
|
240
416
|
let currentIndex = 0
|
|
@@ -242,10 +418,13 @@ export default {
|
|
|
242
418
|
if (
|
|
243
419
|
typeof captions.cues !== 'undefined' &&
|
|
244
420
|
typeof captions.activeCues !== 'undefined' &&
|
|
245
|
-
captions.activeCues.length
|
|
421
|
+
captions.activeCues.length &&
|
|
422
|
+
this.filteredCues.length
|
|
246
423
|
) {
|
|
247
|
-
|
|
248
|
-
|
|
424
|
+
currentIndex = -1
|
|
425
|
+
// Loop over the filtered cues and see if we can find the index
|
|
426
|
+
for (let i = 0; i < this.filteredCues.length; i++) {
|
|
427
|
+
const cue = this.filteredCues[i]
|
|
249
428
|
if (captions.activeCues[0].startTime === cue.startTime) {
|
|
250
429
|
currentIndex = i
|
|
251
430
|
}
|
|
@@ -258,6 +437,7 @@ export default {
|
|
|
258
437
|
// If the captions ref and index is available and the list ref is available
|
|
259
438
|
// Auto-scroll the list to the current caption
|
|
260
439
|
if (
|
|
440
|
+
this.autoscrollState &&
|
|
261
441
|
this.$refs.captionItems &&
|
|
262
442
|
this.$refs.captionItems[currentIndex] &&
|
|
263
443
|
this.$refs.captionItems[currentIndex].$el &&
|
|
@@ -274,17 +454,21 @@ export default {
|
|
|
274
454
|
this.$emit('click:cue', time)
|
|
275
455
|
},
|
|
276
456
|
onClickToggleExpand() {
|
|
277
|
-
this.
|
|
278
|
-
this.$emit('click:expand', this.
|
|
457
|
+
this.expandedState = !this.expandedState
|
|
458
|
+
this.$emit('click:expand', this.expandedState)
|
|
279
459
|
},
|
|
280
460
|
onClickToggleParagraphView() {
|
|
281
|
-
this.
|
|
282
|
-
this.$emit('click:paragraph', this.
|
|
461
|
+
this.paragraphViewState = !this.paragraphViewState
|
|
462
|
+
this.$emit('click:paragraph-view', this.paragraphViewState)
|
|
463
|
+
},
|
|
464
|
+
onClickToggleAutoscroll() {
|
|
465
|
+
this.autoscrollState = !this.autoscrollState
|
|
466
|
+
this.$emit('click:autoscroll', !this.autoscroll)
|
|
467
|
+
},
|
|
468
|
+
onClickClose() {
|
|
469
|
+
this.visibleState = false
|
|
470
|
+
this.$emit('click:close')
|
|
283
471
|
},
|
|
284
|
-
},
|
|
285
|
-
mounted() {
|
|
286
|
-
this.captions = this.value
|
|
287
|
-
this.captionIndex = this.currentCue(this.captions)
|
|
288
472
|
},
|
|
289
473
|
}
|
|
290
474
|
</script>
|
|
@@ -294,28 +478,10 @@ export default {
|
|
|
294
478
|
overflow-y: scroll;
|
|
295
479
|
}
|
|
296
480
|
.captions-list--state-collapsed {
|
|
297
|
-
max-height:
|
|
298
|
-
/* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
|
|
299
|
-
mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
|
|
300
|
-
linear-gradient(
|
|
301
|
-
0deg,
|
|
302
|
-
rgba(0, 0, 0, 0) 0%,
|
|
303
|
-
rgba(0, 0, 0, 1) 20%,
|
|
304
|
-
rgba(0, 0, 0, 1) 80%,
|
|
305
|
-
rgba(0, 0, 0, 0) 100%
|
|
306
|
-
);
|
|
481
|
+
max-height: 15em;
|
|
307
482
|
}
|
|
308
483
|
.captions-list--state-expanded {
|
|
309
484
|
aspect-ratio: 16 / 9;
|
|
310
|
-
/* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
|
|
311
|
-
mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
|
|
312
|
-
linear-gradient(
|
|
313
|
-
0deg,
|
|
314
|
-
rgba(0, 0, 0, 0) 0%,
|
|
315
|
-
rgba(0, 0, 0, 1) 5%,
|
|
316
|
-
rgba(0, 0, 0, 1) 95%,
|
|
317
|
-
rgba(0, 0, 0, 0) 100%
|
|
318
|
-
);
|
|
319
485
|
}
|
|
320
486
|
.caption-text {
|
|
321
487
|
overflow: visible;
|