@mindedge/vuetify-player 0.3.1 → 0.4.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 +90 -50
- package/package.json +1 -1
- package/src/components/Media/CaptionsMenu.vue +269 -99
- package/src/components/Media/Html5Player.vue +454 -304
- 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 +218 -28
- package/src/i18n/en-US.js +9 -0
- package/src/i18n/es-ES.js +12 -0
- package/src/i18n/i18n.js +6 -1
- package/src/i18n/sv-SE.js +11 -0
|
@@ -2,33 +2,40 @@
|
|
|
2
2
|
<v-card>
|
|
3
3
|
<v-card-title>{{ t(language, 'playlist.up_next') }}</v-card-title>
|
|
4
4
|
<v-card-text>
|
|
5
|
-
<v-list>
|
|
5
|
+
<v-list class="playlist-list">
|
|
6
6
|
<v-list-item-group v-model="sourceIndex">
|
|
7
|
-
<v-
|
|
7
|
+
<v-tooltip
|
|
8
|
+
bottom
|
|
8
9
|
v-for="(source, index) of playlist"
|
|
9
10
|
:key="index + 'playlistSources'"
|
|
10
|
-
@click="onPlaylistSelect(index)"
|
|
11
11
|
>
|
|
12
|
-
<
|
|
13
|
-
<v-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
<template #activator="{ on, attrs }">
|
|
13
|
+
<v-list-item
|
|
14
|
+
class="pl-1"
|
|
15
|
+
v-bind="attrs"
|
|
16
|
+
v-on="on"
|
|
17
|
+
@click="onPlaylistSelect(index)"
|
|
16
18
|
>
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
<v-list-item-icon class="ma-2">
|
|
20
|
+
<v-avatar
|
|
21
|
+
v-if="getPoster(source.poster, poster)"
|
|
22
|
+
tile
|
|
23
|
+
>
|
|
24
|
+
<img
|
|
25
|
+
:src="
|
|
26
|
+
getPoster(source.poster, poster)
|
|
27
|
+
"
|
|
28
|
+
/>
|
|
29
|
+
</v-avatar>
|
|
30
|
+
<v-skeleton-loader
|
|
31
|
+
v-if="!getPoster(source.poster, poster)"
|
|
32
|
+
class="ma-3"
|
|
33
|
+
type="avatar"
|
|
34
|
+
tile
|
|
35
|
+
></v-skeleton-loader>
|
|
36
|
+
</v-list-item-icon>
|
|
37
|
+
<v-list-item-content>
|
|
29
38
|
<div
|
|
30
|
-
v-bind="attrs"
|
|
31
|
-
v-on="on"
|
|
32
39
|
class="text-lg-subtitle-1 text-truncate"
|
|
33
40
|
>
|
|
34
41
|
{{
|
|
@@ -36,16 +43,16 @@
|
|
|
36
43
|
t(language, 'playlist.default_name')
|
|
37
44
|
}}
|
|
38
45
|
</div>
|
|
39
|
-
</
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
</
|
|
48
|
-
</v-
|
|
46
|
+
</v-list-item-content>
|
|
47
|
+
</v-list-item>
|
|
48
|
+
</template>
|
|
49
|
+
<span>
|
|
50
|
+
{{
|
|
51
|
+
source.name ||
|
|
52
|
+
t(language, 'playlist.default_name')
|
|
53
|
+
}}
|
|
54
|
+
</span>
|
|
55
|
+
</v-tooltip>
|
|
49
56
|
</v-list-item-group>
|
|
50
57
|
</v-list>
|
|
51
58
|
</v-card-text>
|
|
@@ -122,17 +129,8 @@ export default {
|
|
|
122
129
|
</script>
|
|
123
130
|
|
|
124
131
|
<style scoped>
|
|
125
|
-
.
|
|
126
|
-
max-height:
|
|
132
|
+
.playlist-list {
|
|
133
|
+
max-height: 200px;
|
|
127
134
|
overflow-y: scroll;
|
|
128
|
-
/* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
|
|
129
|
-
mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
|
|
130
|
-
linear-gradient(
|
|
131
|
-
0deg,
|
|
132
|
-
rgba(0, 0, 0, 0) 0%,
|
|
133
|
-
rgba(0, 0, 0, 1) 20%,
|
|
134
|
-
rgba(0, 0, 0, 1) 80%,
|
|
135
|
-
rgba(0, 0, 0, 0) 100%
|
|
136
|
-
);
|
|
137
135
|
}
|
|
138
136
|
</style>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- Settings -->
|
|
3
|
+
<v-menu :attach="attach" top left offset-y :close-on-content-click="false">
|
|
4
|
+
<template #activator="{ on, attrs }">
|
|
5
|
+
<v-btn small text v-bind="attrs" v-on="on">
|
|
6
|
+
<v-icon>mdi-cog</v-icon>
|
|
7
|
+
<span class="d-sr-only">{{
|
|
8
|
+
t(language, 'player.toggle_settings')
|
|
9
|
+
}}</span>
|
|
10
|
+
</v-btn>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<v-list>
|
|
14
|
+
<v-list-item v-if="attributes.captionsmenu">
|
|
15
|
+
<v-list-item-title>
|
|
16
|
+
<v-switch
|
|
17
|
+
:input-value="captionsVisible"
|
|
18
|
+
:label="t(language, 'captions.show_transcript')"
|
|
19
|
+
@change="$emit('update:captions-visible', $event)"
|
|
20
|
+
></v-switch>
|
|
21
|
+
</v-list-item-title>
|
|
22
|
+
</v-list-item>
|
|
23
|
+
<v-list-item>
|
|
24
|
+
<v-list-item-title>
|
|
25
|
+
<v-icon>mdi-play-speed</v-icon>
|
|
26
|
+
{{ t(language, 'player.playback_speed') }}
|
|
27
|
+
</v-list-item-title>
|
|
28
|
+
</v-list-item>
|
|
29
|
+
<v-list-item>
|
|
30
|
+
<v-list-item-title class="text-center">
|
|
31
|
+
<v-btn
|
|
32
|
+
small
|
|
33
|
+
:disabled="state.playbackRateIndex === 0"
|
|
34
|
+
@click="onPlaybackSpeed(state.playbackRateIndex - 1)"
|
|
35
|
+
>
|
|
36
|
+
<v-icon> mdi-clock-minus-outline </v-icon>
|
|
37
|
+
<span class="d-sr-only">{{
|
|
38
|
+
t(language, 'player.playback_decrease')
|
|
39
|
+
}}</span>
|
|
40
|
+
</v-btn>
|
|
41
|
+
<span class="pl-2 pr-2"
|
|
42
|
+
>{{
|
|
43
|
+
attributes.playbackrates[state.playbackRateIndex]
|
|
44
|
+
}}x</span
|
|
45
|
+
>
|
|
46
|
+
<v-btn
|
|
47
|
+
small
|
|
48
|
+
:disabled="
|
|
49
|
+
state.playbackRateIndex >=
|
|
50
|
+
attributes.playbackrates.length - 1
|
|
51
|
+
"
|
|
52
|
+
@click="onPlaybackSpeed(state.playbackRateIndex + 1)"
|
|
53
|
+
>
|
|
54
|
+
<v-icon> mdi-clock-plus-outline </v-icon>
|
|
55
|
+
<span class="d-sr-only">{{
|
|
56
|
+
t(language, 'player.playback_increase')
|
|
57
|
+
}}</span>
|
|
58
|
+
</v-btn>
|
|
59
|
+
</v-list-item-title>
|
|
60
|
+
</v-list-item>
|
|
61
|
+
</v-list>
|
|
62
|
+
</v-menu>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<script>
|
|
66
|
+
import { t } from '../../i18n/i18n'
|
|
67
|
+
|
|
68
|
+
export default {
|
|
69
|
+
name: 'SettingsMenu',
|
|
70
|
+
components: {},
|
|
71
|
+
props: {
|
|
72
|
+
language: { type: String, required: false, default: 'en-US' },
|
|
73
|
+
attach: { type: null, required: false, default: false },
|
|
74
|
+
state: {
|
|
75
|
+
type: Object,
|
|
76
|
+
required: true,
|
|
77
|
+
},
|
|
78
|
+
attributes: {
|
|
79
|
+
type: Object,
|
|
80
|
+
required: true,
|
|
81
|
+
},
|
|
82
|
+
captionsVisible: { type: Boolean, required: false, default: undefined },
|
|
83
|
+
},
|
|
84
|
+
emits: ['update:captions-visible', 'change:playback-rate-index'],
|
|
85
|
+
watch: {},
|
|
86
|
+
computed: {},
|
|
87
|
+
data() {
|
|
88
|
+
return { t }
|
|
89
|
+
},
|
|
90
|
+
beforeMount() {},
|
|
91
|
+
mounted() {},
|
|
92
|
+
methods: {
|
|
93
|
+
onPlaybackSpeed(index) {
|
|
94
|
+
this.$emit('change:playback-rate-index', index)
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
</script>
|
|
@@ -34,9 +34,13 @@ export default {
|
|
|
34
34
|
watch: {},
|
|
35
35
|
computed: {
|
|
36
36
|
playerClass() {
|
|
37
|
-
let classList = 'player-' + this.
|
|
37
|
+
let classList = 'player-' + this.resolvedType
|
|
38
38
|
return classList
|
|
39
39
|
},
|
|
40
|
+
resolvedType() {
|
|
41
|
+
// Youtube is always a video
|
|
42
|
+
return 'video'
|
|
43
|
+
},
|
|
40
44
|
},
|
|
41
45
|
data() {
|
|
42
46
|
return {
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<v-row>
|
|
4
|
-
<v-col
|
|
3
|
+
<v-row tabindex="0">
|
|
4
|
+
<v-col cols="12">
|
|
5
|
+
<div v-if="parseSourceType(current.src.sources) === null">
|
|
6
|
+
<div class="player-skeleton--no-source">
|
|
7
|
+
<slot name="no-source">
|
|
8
|
+
<div>
|
|
9
|
+
<v-icon x-large>mdi-cloud-question</v-icon>
|
|
10
|
+
<p>
|
|
11
|
+
{{ t(language, 'player.not_configured') }}
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
</slot>
|
|
15
|
+
</div>
|
|
16
|
+
<v-skeleton-loader
|
|
17
|
+
type="image, image, list-item-avatar"
|
|
18
|
+
class="player-skeleton"
|
|
19
|
+
></v-skeleton-loader>
|
|
20
|
+
</div>
|
|
5
21
|
<YoutubePlayer
|
|
6
22
|
ref="youtubePlayer"
|
|
7
23
|
v-if="parseSourceType(current.src.sources) === 'youtube'"
|
|
@@ -9,6 +25,9 @@
|
|
|
9
25
|
:type="current.type"
|
|
10
26
|
:attributes="current.attributes"
|
|
11
27
|
:src="current.src"
|
|
28
|
+
:elevation="flat ? 0 : elevation"
|
|
29
|
+
@focusin="onFocusin"
|
|
30
|
+
@focusout="onFocusout"
|
|
12
31
|
@click:fullscreen="onFullscreen"
|
|
13
32
|
></YoutubePlayer>
|
|
14
33
|
<Html5Player
|
|
@@ -18,6 +37,14 @@
|
|
|
18
37
|
:type="current.type"
|
|
19
38
|
:attributes="current.attributes"
|
|
20
39
|
:src="current.src"
|
|
40
|
+
:captions-expanded.sync="captionsExpandedState"
|
|
41
|
+
:captions-hide-expand="captionsHideExpand"
|
|
42
|
+
:captions-paragraph-view="captionsParagraphView"
|
|
43
|
+
:captions-hide-paragraph-view="captionsHideParagraphView"
|
|
44
|
+
:captions-autoscroll="captionsAutoscroll"
|
|
45
|
+
:captions-hide-autoscroll="captionsHideAutoscroll"
|
|
46
|
+
:captions-visible.sync="captionsVisibleState"
|
|
47
|
+
:elevation="flat ? 0 : elevation"
|
|
21
48
|
@load="$emit('load', $event)"
|
|
22
49
|
@ended="onEnded"
|
|
23
50
|
@loadeddata="onLoadeddata"
|
|
@@ -37,19 +64,29 @@
|
|
|
37
64
|
@abort="$emit('abort', $event)"
|
|
38
65
|
@mouseover="$emit('mouseover', $event)"
|
|
39
66
|
@mouseout="$emit('mouseout', $event)"
|
|
67
|
+
@update:captions-expanded="
|
|
68
|
+
$emit('update:captions-expanded', $event)
|
|
69
|
+
"
|
|
70
|
+
@update:captions-paragraph-view="
|
|
71
|
+
$emit('update:captions-paragraph-view', $event)
|
|
72
|
+
"
|
|
73
|
+
@update:captions-autoscroll="
|
|
74
|
+
$emit('update:captions-autoscroll', $event)
|
|
75
|
+
"
|
|
40
76
|
@click:fullscreen="onFullscreen"
|
|
41
77
|
@click:pictureinpicture="onPictureInPicture"
|
|
42
78
|
@click:remoteplayback="onRemoteplayback"
|
|
43
79
|
@click:captions-expand="onClickCaptionsExpand"
|
|
44
|
-
@click:captions-paragraph="onClickCaptionsParagraph"
|
|
80
|
+
@click:captions-paragraph-view="onClickCaptionsParagraph"
|
|
81
|
+
@click:captions-autoscroll="onClickCaptionsAutoscroll"
|
|
82
|
+
@click:captions-close="onClickCaptionsClose"
|
|
83
|
+
@focusin="onFocusin"
|
|
84
|
+
@focusout="onFocusout"
|
|
45
85
|
></Html5Player>
|
|
46
86
|
</v-col>
|
|
47
87
|
|
|
48
88
|
<!-- Playlist stuff -->
|
|
49
|
-
<v-col
|
|
50
|
-
v-if="playlistmenu && playlist.length > 1"
|
|
51
|
-
:cols="playlistCols"
|
|
52
|
-
>
|
|
89
|
+
<v-col v-if="showPlaylist" cols="12" class="mt-0 pt-0">
|
|
53
90
|
<PlaylistMenu
|
|
54
91
|
v-model="sourceIndex"
|
|
55
92
|
:language="language"
|
|
@@ -63,6 +100,7 @@
|
|
|
63
100
|
</template>
|
|
64
101
|
|
|
65
102
|
<script>
|
|
103
|
+
import { t } from '../i18n/i18n'
|
|
66
104
|
import YoutubePlayer from './Media/YoutubePlayer.vue'
|
|
67
105
|
import Html5Player from './Media/Html5Player.vue'
|
|
68
106
|
import PlaylistMenu from './Media/PlaylistMenu.vue'
|
|
@@ -90,7 +128,7 @@ export default {
|
|
|
90
128
|
return []
|
|
91
129
|
},
|
|
92
130
|
},
|
|
93
|
-
type: { type: String, required: false, default: '
|
|
131
|
+
type: { type: String, required: false, default: 'auto' }, // Allowed auto|video|audio. In audio mode the player has a max-height of 40px
|
|
94
132
|
autoplay: { type: Boolean, required: false, default: false }, // Autoplay on load. It's in the spec but DON'T USE THIS
|
|
95
133
|
autopictureinpicture: {
|
|
96
134
|
type: Boolean,
|
|
@@ -123,6 +161,42 @@ export default {
|
|
|
123
161
|
poster: { type: String, required: false, default: '' }, // Overridden with the playlist.poster if one is set there
|
|
124
162
|
preload: { type: String, required: false, default: '' },
|
|
125
163
|
captionsmenu: { type: Boolean, required: false, default: true }, // Show the captions below the video
|
|
164
|
+
captionsExpanded: {
|
|
165
|
+
type: Boolean,
|
|
166
|
+
required: false,
|
|
167
|
+
default: undefined,
|
|
168
|
+
},
|
|
169
|
+
captionsHideExpand: { type: Boolean, required: false, default: true },
|
|
170
|
+
captionsParagraphView: {
|
|
171
|
+
type: Boolean,
|
|
172
|
+
required: false,
|
|
173
|
+
default: undefined,
|
|
174
|
+
},
|
|
175
|
+
captionsHideParagraphView: {
|
|
176
|
+
type: Boolean,
|
|
177
|
+
required: false,
|
|
178
|
+
default: false,
|
|
179
|
+
},
|
|
180
|
+
captionsAutoscroll: {
|
|
181
|
+
type: Boolean,
|
|
182
|
+
required: false,
|
|
183
|
+
default: undefined,
|
|
184
|
+
},
|
|
185
|
+
captionsHideAutoscroll: {
|
|
186
|
+
type: Boolean,
|
|
187
|
+
required: false,
|
|
188
|
+
default: false,
|
|
189
|
+
},
|
|
190
|
+
captionsHideClose: {
|
|
191
|
+
type: Boolean,
|
|
192
|
+
required: false,
|
|
193
|
+
default: false,
|
|
194
|
+
},
|
|
195
|
+
captionsVisible: {
|
|
196
|
+
type: Boolean,
|
|
197
|
+
required: false,
|
|
198
|
+
default: true,
|
|
199
|
+
},
|
|
126
200
|
playlistmenu: { type: Boolean, required: false, default: true }, // Show the playlist menu if there's multiple videos
|
|
127
201
|
playlistautoadvance: { type: Boolean, required: false, default: true }, // Play the next source group
|
|
128
202
|
playbackrates: {
|
|
@@ -132,7 +206,40 @@ export default {
|
|
|
132
206
|
return [0.5, 1, 1.5, 2]
|
|
133
207
|
},
|
|
134
208
|
}, // Default playback speeds
|
|
209
|
+
elevation: { type: [Number, String], required: false, default: 2 },
|
|
210
|
+
flat: { type: Boolean, required: false, default: false },
|
|
135
211
|
},
|
|
212
|
+
emits: [
|
|
213
|
+
'load',
|
|
214
|
+
'loadeddata',
|
|
215
|
+
'loadedmetadata',
|
|
216
|
+
'play',
|
|
217
|
+
'pause',
|
|
218
|
+
'seeking',
|
|
219
|
+
'timeupdate',
|
|
220
|
+
'progress',
|
|
221
|
+
'canplay',
|
|
222
|
+
'waiting',
|
|
223
|
+
'canplaythrough',
|
|
224
|
+
'error',
|
|
225
|
+
'emptied',
|
|
226
|
+
'ratechange',
|
|
227
|
+
'stalled',
|
|
228
|
+
'abort',
|
|
229
|
+
'mouseover',
|
|
230
|
+
'mouseout',
|
|
231
|
+
'ended',
|
|
232
|
+
'click:pictureinpicture',
|
|
233
|
+
'click:fullscreen',
|
|
234
|
+
'click:captions-expand',
|
|
235
|
+
'click:captions-paragraph-view',
|
|
236
|
+
'click:captions-autoscroll',
|
|
237
|
+
'click:captions-close',
|
|
238
|
+
'update:captions-expanded',
|
|
239
|
+
'update:captions-paragraph-view',
|
|
240
|
+
'update:captions-autoscroll',
|
|
241
|
+
'update:captions-visible',
|
|
242
|
+
],
|
|
136
243
|
watch: {},
|
|
137
244
|
computed: {
|
|
138
245
|
player() {
|
|
@@ -180,17 +287,9 @@ export default {
|
|
|
180
287
|
},
|
|
181
288
|
playlistCols() {
|
|
182
289
|
// Captions collapsed, playlist will appear on the right
|
|
183
|
-
if (
|
|
184
|
-
!this.captionsExpanded &&
|
|
185
|
-
this.playlistmenu &&
|
|
186
|
-
this.playlist.length > 1
|
|
187
|
-
) {
|
|
290
|
+
if (!this.captionsExpandedState && this.showPlaylist) {
|
|
188
291
|
return 4
|
|
189
|
-
} else if (
|
|
190
|
-
this.captionsExpanded &&
|
|
191
|
-
this.playlistmenu &&
|
|
192
|
-
this.playlist.length > 1
|
|
193
|
-
) {
|
|
292
|
+
} else if (this.captionsExpandedState && this.showPlaylist) {
|
|
194
293
|
// Captions expanded, playlist will appear as a new row on the bottom of everything
|
|
195
294
|
return 12
|
|
196
295
|
} else {
|
|
@@ -198,21 +297,52 @@ export default {
|
|
|
198
297
|
}
|
|
199
298
|
},
|
|
200
299
|
playerCols() {
|
|
201
|
-
if (
|
|
202
|
-
this.captionsExpanded ||
|
|
203
|
-
!this.playlistmenu ||
|
|
204
|
-
this.playlist.length <= 1
|
|
205
|
-
) {
|
|
300
|
+
if (this.captionsExpandedState || !this.showPlaylist) {
|
|
206
301
|
return 12
|
|
207
302
|
} else {
|
|
208
303
|
return 8
|
|
209
304
|
}
|
|
210
305
|
},
|
|
306
|
+
captionsVisibleState: {
|
|
307
|
+
get() {
|
|
308
|
+
if (typeof this.captionsVisible !== 'undefined') {
|
|
309
|
+
return this.captionsVisible
|
|
310
|
+
} else {
|
|
311
|
+
return this.captions.visible
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
set(v) {
|
|
315
|
+
this.$emit('update:captions-visible', v)
|
|
316
|
+
this.captions.visible = v
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
captionsExpandedState: {
|
|
320
|
+
get() {
|
|
321
|
+
if (typeof this.captionsExpanded !== 'undefined') {
|
|
322
|
+
return this.captionsExpanded
|
|
323
|
+
} else {
|
|
324
|
+
return this.captions.expanded
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
set(v) {
|
|
328
|
+
this.$emit('update:captions-expanded', v)
|
|
329
|
+
this.captions.expanded = v
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
showPlaylist() {
|
|
333
|
+
return this.playlistmenu && this.playlist.length > 1
|
|
334
|
+
},
|
|
211
335
|
},
|
|
212
336
|
data() {
|
|
213
337
|
return {
|
|
338
|
+
t,
|
|
214
339
|
sourceIndex: 0,
|
|
215
|
-
|
|
340
|
+
captions: {
|
|
341
|
+
visible: true,
|
|
342
|
+
expanded: false,
|
|
343
|
+
},
|
|
344
|
+
mediaFocus: false,
|
|
345
|
+
keyListener: null,
|
|
216
346
|
}
|
|
217
347
|
},
|
|
218
348
|
methods: {
|
|
@@ -273,16 +403,25 @@ export default {
|
|
|
273
403
|
}
|
|
274
404
|
},
|
|
275
405
|
onClickCaptionsExpand(expanded) {
|
|
276
|
-
this.captionsExpanded = expanded
|
|
277
406
|
this.$emit('click:captions-expand', expanded)
|
|
278
407
|
},
|
|
279
408
|
onClickCaptionsParagraph(isParagraph) {
|
|
280
|
-
this.$emit('click:captions-paragraph', isParagraph)
|
|
409
|
+
this.$emit('click:captions-paragraph-view', isParagraph)
|
|
410
|
+
},
|
|
411
|
+
onClickCaptionsAutoscroll(autoscroll) {
|
|
412
|
+
this.$emit('click:captions-autoscroll', autoscroll)
|
|
413
|
+
},
|
|
414
|
+
onClickCaptionsClose() {
|
|
415
|
+
this.$emit('click:captions-close')
|
|
281
416
|
},
|
|
282
417
|
onPlaylistSelect(index) {
|
|
283
418
|
this.sourceIndex = parseInt(index)
|
|
284
|
-
|
|
285
|
-
|
|
419
|
+
|
|
420
|
+
// If we give a bad media type then the player won't resolve
|
|
421
|
+
if (this.player && typeof this.player.load !== 'undefined') {
|
|
422
|
+
this.player.load()
|
|
423
|
+
this.player.play()
|
|
424
|
+
}
|
|
286
425
|
},
|
|
287
426
|
parseSourceType(sources) {
|
|
288
427
|
const ytRegex =
|
|
@@ -304,6 +443,44 @@ export default {
|
|
|
304
443
|
return 'html5'
|
|
305
444
|
}
|
|
306
445
|
},
|
|
446
|
+
onFocusin() {
|
|
447
|
+
this.mediaFocus = true
|
|
448
|
+
if (this.player && this.player.$el) {
|
|
449
|
+
this.player.$el.addEventListener('keydown', this.onKeydown)
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
onFocusout() {
|
|
453
|
+
this.mediaFocus = false
|
|
454
|
+
if (this.player && this.player.$el) {
|
|
455
|
+
this.player.$el.removeEventListener('keydown', this.onKeydown)
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
onKeydown(e) {
|
|
459
|
+
// Only process keyboard events if the media is focused
|
|
460
|
+
// This is just in case the media lost focus but the event listener wasn't removed for some reason
|
|
461
|
+
if (this.mediaFocus) {
|
|
462
|
+
e.preventDefault()
|
|
463
|
+
const map = {
|
|
464
|
+
Space: { cb: this.player.playToggle, params: [e] },
|
|
465
|
+
KeyK: { cb: this.player.playToggle, params: [e] },
|
|
466
|
+
KeyM: { cb: this.player.muteToggle, params: [e] },
|
|
467
|
+
ArrowLeft: { cb: this.player.rewind, params: [5] },
|
|
468
|
+
ArrowRight: { cb: this.player.fastForward, params: [5] },
|
|
469
|
+
KeyJ: { cb: this.player.rewind, params: [10] },
|
|
470
|
+
KeyL: { cb: this.player.fastForward, params: [10] },
|
|
471
|
+
ArrowUp: { cb: this.player.volumeAdjust, params: [0.1] },
|
|
472
|
+
ArrowDown: { cb: this.player.volumeAdjust, params: [-0.1] },
|
|
473
|
+
KeyF: { cb: this.player.fullscreenToggle, params: [e] },
|
|
474
|
+
KeyC: { cb: this.player.CCToggle, params: [e] },
|
|
475
|
+
}
|
|
476
|
+
if (
|
|
477
|
+
typeof map[e.code] !== 'undefined' &&
|
|
478
|
+
typeof map[e.code].cb !== 'undefined'
|
|
479
|
+
) {
|
|
480
|
+
map[e.code].cb(...map[e.code].params)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
},
|
|
307
484
|
},
|
|
308
485
|
beforeCreate() {},
|
|
309
486
|
beforeMount() {},
|
|
@@ -311,3 +488,16 @@ export default {
|
|
|
311
488
|
beforeDestroy() {},
|
|
312
489
|
}
|
|
313
490
|
</script>
|
|
491
|
+
|
|
492
|
+
<style scoped>
|
|
493
|
+
.player-skeleton {
|
|
494
|
+
aspect-ratio: 16 / 9;
|
|
495
|
+
overflow: hidden;
|
|
496
|
+
}
|
|
497
|
+
.player-skeleton--no-source {
|
|
498
|
+
height: 0px;
|
|
499
|
+
position: relative;
|
|
500
|
+
top: 100px;
|
|
501
|
+
text-align: center;
|
|
502
|
+
}
|
|
503
|
+
</style>
|
package/src/i18n/en-US.js
CHANGED
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
next: 'Play next item in playlist',
|
|
11
11
|
},
|
|
12
12
|
player: {
|
|
13
|
+
not_configured: 'Media not configured',
|
|
13
14
|
playback_speed: 'Playback Speed',
|
|
14
15
|
playback_decrease: 'Decrease playback speed',
|
|
15
16
|
playback_increase: 'Increase playback speed',
|
|
@@ -27,9 +28,17 @@ export default {
|
|
|
27
28
|
no_support: "Sorry, your browser doesn't support embedded videos.",
|
|
28
29
|
},
|
|
29
30
|
captions: {
|
|
31
|
+
show_transcript: 'Show Transcript',
|
|
32
|
+
close: 'Close',
|
|
33
|
+
search: 'Search',
|
|
34
|
+
none_found: "No captions found for '{0}'",
|
|
30
35
|
expand: 'Expand',
|
|
31
36
|
collapse: 'Collapse',
|
|
32
37
|
view_as_paragraph: 'View as paragraph',
|
|
33
38
|
view_as_captions: 'View as captions',
|
|
39
|
+
enable_autoscroll: 'Enable auto-scroll for transcript as media plays',
|
|
40
|
+
disable_autoscroll: 'Disable auto-scroll for transcript as media plays',
|
|
41
|
+
autoscroll_enabled: 'Autoscroll transcript enabled',
|
|
42
|
+
autoscroll_disabled: 'Autoscroll transcript disabled',
|
|
34
43
|
},
|
|
35
44
|
}
|
package/src/i18n/es-ES.js
CHANGED
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
next: 'Reproducir el siguiente elemento en la lista de reproducción',
|
|
11
11
|
},
|
|
12
12
|
player: {
|
|
13
|
+
not_configured: 'Medios no configurados',
|
|
13
14
|
playback_speed: 'Velocidad de reproducción',
|
|
14
15
|
playback_decrease: 'Disminuir la velocidad de reproducción',
|
|
15
16
|
playback_increase: 'Aumentar la velocidad de reproducción',
|
|
@@ -27,9 +28,20 @@ export default {
|
|
|
27
28
|
no_support: 'Lo sentimos, su navegador no admite vídeos incrustados. ',
|
|
28
29
|
},
|
|
29
30
|
captions: {
|
|
31
|
+
show_transcript: 'Mostrar transcripción',
|
|
32
|
+
close: 'Cerca',
|
|
33
|
+
search: 'Buscar',
|
|
34
|
+
none_found: "No se encontraron subtítulos para '{0}'",
|
|
30
35
|
expand: 'Expandir',
|
|
31
36
|
collapse: 'Colapsar',
|
|
32
37
|
view_as_paragraph: 'Ver como párrafo',
|
|
33
38
|
view_as_captions: 'Ver como subtítulos',
|
|
39
|
+
enable_autoscroll:
|
|
40
|
+
'Habilite el desplazamiento automático para la transcripción mientras se reproducen los medios',
|
|
41
|
+
disable_autoscroll:
|
|
42
|
+
'Deshabilite el desplazamiento automático para la transcripción mientras se reproducen los medios',
|
|
43
|
+
autoscroll_enabled:
|
|
44
|
+
'Transcripción con desplazamiento automático habilitada',
|
|
45
|
+
autoscroll_disabled: 'Transcripción automática deshabilitado',
|
|
34
46
|
},
|
|
35
47
|
}
|
package/src/i18n/i18n.js
CHANGED
|
@@ -18,7 +18,7 @@ function get(obj, path) {
|
|
|
18
18
|
return get(obj[parts[0]], parts.slice(1).join('.'))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const t = (lang, path) => {
|
|
21
|
+
const t = (lang, path, replacements = []) => {
|
|
22
22
|
if (typeof i18n[lang] === 'undefined') {
|
|
23
23
|
console.warn(
|
|
24
24
|
'[VuetifyPlayer] No support for locale ' +
|
|
@@ -35,6 +35,11 @@ const t = (lang, path) => {
|
|
|
35
35
|
console.warn(
|
|
36
36
|
'[VuetifyPlayer] localization path ' + path + ' does not exist'
|
|
37
37
|
)
|
|
38
|
+
} else {
|
|
39
|
+
// Apply replacements
|
|
40
|
+
for (const key in replacements) {
|
|
41
|
+
localized = localized.replaceAll('{' + key + '}', replacements[key])
|
|
42
|
+
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
return localized
|
package/src/i18n/sv-SE.js
CHANGED
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
next: 'Spela nästa',
|
|
11
11
|
},
|
|
12
12
|
player: {
|
|
13
|
+
not_configured: 'Media inte konfigurerad',
|
|
13
14
|
playback_speed: 'Uppspelningshastighet',
|
|
14
15
|
playback_decrease: 'Minska uppspelningshastigheten',
|
|
15
16
|
playback_increase: 'Öka uppspelningshastigheten',
|
|
@@ -27,9 +28,19 @@ export default {
|
|
|
27
28
|
no_support: 'Tyvärr, din webbläsare stöder inte inbäddade videor.',
|
|
28
29
|
},
|
|
29
30
|
captions: {
|
|
31
|
+
show_transcript: 'Visa avskrift',
|
|
32
|
+
close: 'Stäng',
|
|
33
|
+
search: 'Sök',
|
|
34
|
+
none_found: "Inga bildtexter hittades för '{0}'",
|
|
30
35
|
expand: 'Bygga ut',
|
|
31
36
|
collapse: 'Kollaps',
|
|
32
37
|
view_as_paragraph: 'Visa som stycke',
|
|
33
38
|
view_as_captions: 'Visa som bildtexter',
|
|
39
|
+
enable_autoscroll:
|
|
40
|
+
'Aktivera automatisk rullning för transkription när media spelas upp',
|
|
41
|
+
disable_autoscroll:
|
|
42
|
+
'Inaktivera automatisk rullning för transkribering när media spelas upp',
|
|
43
|
+
autoscroll_enabled: 'Autoscroll-transkription aktiverad',
|
|
44
|
+
autoscroll_disabled: 'Autoscroll-transkription inaktiverad',
|
|
34
45
|
},
|
|
35
46
|
}
|