@mindedge/vuetify-player 0.4.10 → 0.5.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
CHANGED
|
@@ -26,6 +26,7 @@ An accessible, localized, full featured media player with Vuetifyjs
|
|
|
26
26
|
| webm | wav | jpg |
|
|
27
27
|
| ogg | ogg | gif (+ animated) |
|
|
28
28
|
| YouTube URL | | |
|
|
29
|
+
| Vimeo URL | | |
|
|
29
30
|
|
|
30
31
|
## Quick Start
|
|
31
32
|
|
|
@@ -244,9 +245,11 @@ See [Full media `src` structure for where the ads array is placed](#full-media-s
|
|
|
244
245
|
| `loadeddata` | `Event` | When the frame at the current playback position of the media has finished loading; often the first frame |
|
|
245
246
|
| `loadedmetadata` | `Event` | When the metadata has been loaded |
|
|
246
247
|
| `play` | `Event` | The media has received a request to start playing |
|
|
248
|
+
| `playing` | `Event` | The media playback is first started, and whenever it is restarted |
|
|
247
249
|
| `pause` | `Event` | Playback has been suspended |
|
|
248
250
|
| `progress` | `Event` | The progress event is fired periodically as the browser loads a resource. |
|
|
249
|
-
| `seeking` | `Event` | Playback
|
|
251
|
+
| `seeking` | `Event` | Playback is currently beeing seeked |
|
|
252
|
+
| `seeked` | `Event` | Playback has moved to a new location |
|
|
250
253
|
| `timeupdate` | `Object` | The current time was changed. Object contains { event: Event, current_percent: Number } |
|
|
251
254
|
| `ratechange` | `Number` | The playback speed multiplier |
|
|
252
255
|
| `stalled` | `Event` | The browser tried to download but has not received data yet |
|
package/package.json
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
<div
|
|
21
21
|
v-if="resolvedType === 'video' && state.replay"
|
|
22
22
|
class="player-overlay"
|
|
23
|
+
role="button"
|
|
24
|
+
@click="play"
|
|
23
25
|
>
|
|
24
26
|
<div class="player-overlay--icon">
|
|
25
27
|
<v-icon class="player-overlay--play-icon">
|
|
@@ -30,10 +32,13 @@
|
|
|
30
32
|
<div
|
|
31
33
|
v-if="
|
|
32
34
|
resolvedType === 'video' &&
|
|
35
|
+
state.paused &&
|
|
33
36
|
!state.replay &&
|
|
34
|
-
|
|
37
|
+
player.currentTime === 0
|
|
35
38
|
"
|
|
36
39
|
class="player-overlay"
|
|
40
|
+
role="button"
|
|
41
|
+
@click="play"
|
|
37
42
|
>
|
|
38
43
|
<div class="player-overlay--icon">
|
|
39
44
|
<v-icon class="player-overlay--play-icon">
|
|
@@ -62,6 +67,7 @@
|
|
|
62
67
|
:preload="attributes.preload"
|
|
63
68
|
@click="playToggle"
|
|
64
69
|
@seeking="onSeeking"
|
|
70
|
+
@seeked="onSeeked"
|
|
65
71
|
@timeupdate="onTimeupdate"
|
|
66
72
|
@progress="onMediaProgress"
|
|
67
73
|
@loadedmetadata="onLoadedmetadata"
|
|
@@ -644,6 +650,7 @@ export default {
|
|
|
644
650
|
'ratechange',
|
|
645
651
|
'timeupdate',
|
|
646
652
|
'seeking',
|
|
653
|
+
'seeked',
|
|
647
654
|
'progress',
|
|
648
655
|
'volumechange',
|
|
649
656
|
'cuechange',
|
|
@@ -1067,6 +1074,9 @@ export default {
|
|
|
1067
1074
|
onSeeking(e) {
|
|
1068
1075
|
this.$emit('seeking', e)
|
|
1069
1076
|
},
|
|
1077
|
+
onSeeked(e) {
|
|
1078
|
+
this.$emit('seeked', e)
|
|
1079
|
+
},
|
|
1070
1080
|
onMediaProgress(e) {
|
|
1071
1081
|
this.$emit('progress', e)
|
|
1072
1082
|
},
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-container>
|
|
3
|
+
<v-responsive>
|
|
4
|
+
<v-skeleton-loader
|
|
5
|
+
v-if="!player.ready"
|
|
6
|
+
class="mx-auto player-skeleton"
|
|
7
|
+
type="image"
|
|
8
|
+
></v-skeleton-loader>
|
|
9
|
+
|
|
10
|
+
<div :id="player.id" :class="playerClass"></div>
|
|
11
|
+
</v-responsive>
|
|
12
|
+
</v-container>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
export default {
|
|
17
|
+
name: 'VimeoPlayer',
|
|
18
|
+
props: {
|
|
19
|
+
language: { type: String, required: false, default: 'en-US' },
|
|
20
|
+
type: {
|
|
21
|
+
type: String,
|
|
22
|
+
required: false,
|
|
23
|
+
default: 'video',
|
|
24
|
+
},
|
|
25
|
+
attributes: {
|
|
26
|
+
type: Object,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
src: {
|
|
30
|
+
type: Object,
|
|
31
|
+
required: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
emits: [
|
|
35
|
+
'loadeddata',
|
|
36
|
+
'play',
|
|
37
|
+
'pause',
|
|
38
|
+
'progress',
|
|
39
|
+
'volumechange',
|
|
40
|
+
'ended',
|
|
41
|
+
'seeking',
|
|
42
|
+
'seeked',
|
|
43
|
+
'timeupdate',
|
|
44
|
+
],
|
|
45
|
+
watch: {},
|
|
46
|
+
computed: {
|
|
47
|
+
playerClass() {
|
|
48
|
+
let classList = 'player-' + this.resolvedType
|
|
49
|
+
return classList
|
|
50
|
+
},
|
|
51
|
+
resolvedType() {
|
|
52
|
+
// vimeo is always a video
|
|
53
|
+
return 'video'
|
|
54
|
+
},
|
|
55
|
+
aspectRatio() {
|
|
56
|
+
if (this.player.height === 0 || this.player.width === 0) {
|
|
57
|
+
return 16 / 9
|
|
58
|
+
} else {
|
|
59
|
+
return this.player.width / this.player.height
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
data() {
|
|
64
|
+
return {
|
|
65
|
+
player: {
|
|
66
|
+
id:
|
|
67
|
+
'vimeo-player-' +
|
|
68
|
+
Math.floor(Math.random() * 10000000) +
|
|
69
|
+
1000000,
|
|
70
|
+
vimeo: {},
|
|
71
|
+
tag: {},
|
|
72
|
+
scriptTag: {},
|
|
73
|
+
loaded: false,
|
|
74
|
+
done: false,
|
|
75
|
+
ready: false,
|
|
76
|
+
height: 0,
|
|
77
|
+
width: 0,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
mounted() {
|
|
82
|
+
this.loadAPI()
|
|
83
|
+
},
|
|
84
|
+
beforeDestroy() {
|
|
85
|
+
if (this.player.loaded) {
|
|
86
|
+
this.player.vimeo.off('seeked')
|
|
87
|
+
this.player.vimeo.off('timeupdate')
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
methods: {
|
|
91
|
+
parseVideoSource(src) {
|
|
92
|
+
const result = {
|
|
93
|
+
videoId: null,
|
|
94
|
+
listId: null,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!src.sources || !src.sources.length || !src.sources[0].src) {
|
|
98
|
+
return result
|
|
99
|
+
} else {
|
|
100
|
+
let url = src.sources[0].src
|
|
101
|
+
const regexId =
|
|
102
|
+
/(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|video\/|)(\d+)(?:|\/\?)/
|
|
103
|
+
const idMatch = url.match(regexId)
|
|
104
|
+
|
|
105
|
+
if (idMatch[4]) {
|
|
106
|
+
result.videoId = idMatch[4]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const regexPlaylist = /[?&]list=([^#&?]+)/
|
|
110
|
+
const playlistMatch = url.match(regexPlaylist)
|
|
111
|
+
|
|
112
|
+
if (playlistMatch && playlistMatch[1]) {
|
|
113
|
+
result.listId = playlistMatch[1]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return result
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
onreadystatechange() {
|
|
120
|
+
if (
|
|
121
|
+
!this.player.loaded &&
|
|
122
|
+
(this.player.tag.readyState === 'complete' ||
|
|
123
|
+
this.player.tag.readyState === 'loaded')
|
|
124
|
+
) {
|
|
125
|
+
this.player.loaded = true
|
|
126
|
+
setTimeout(this.tagReady, 500)
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
onload() {
|
|
130
|
+
if (!this.player.loaded) {
|
|
131
|
+
this.player.loaded = true
|
|
132
|
+
setTimeout(this.tagReady, 500)
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
async tagReady() {
|
|
136
|
+
const source = this.parseVideoSource(this.src)
|
|
137
|
+
this.player.vimeo = new window.Vimeo.Player(this.player.id, {
|
|
138
|
+
id: source.videoId,
|
|
139
|
+
responsive: true,
|
|
140
|
+
})
|
|
141
|
+
this.player.vimeo.on('seeked', this.onSeek)
|
|
142
|
+
this.player.vimeo.on('timeupdate', this.onTimeupdate)
|
|
143
|
+
|
|
144
|
+
this.player.vimeo.on('ended', this.onEnded)
|
|
145
|
+
this.player.vimeo.on('loaded', this.onLoaded)
|
|
146
|
+
this.player.vimeo.on('play', this.onPlay)
|
|
147
|
+
this.player.vimeo.on('pause', this.onPause)
|
|
148
|
+
this.player.vimeo.on('progress', this.onProgress)
|
|
149
|
+
this.player.vimeo.on('volumechange', this.onVolumechange)
|
|
150
|
+
this.player.vimeo.on('error', this.onError)
|
|
151
|
+
|
|
152
|
+
this.player.ready = true
|
|
153
|
+
},
|
|
154
|
+
loadAPI() {
|
|
155
|
+
if (this.player.loaded) {
|
|
156
|
+
this.tagReady()
|
|
157
|
+
} else {
|
|
158
|
+
this.player.tag = document.createElement('script')
|
|
159
|
+
|
|
160
|
+
this.player.tag.src = 'https://player.vimeo.com/api/player.js'
|
|
161
|
+
this.player.scriptTag =
|
|
162
|
+
document.getElementsByTagName('script')[0]
|
|
163
|
+
|
|
164
|
+
// Make sure script tag was successfully created
|
|
165
|
+
if (this.player.scriptTag) {
|
|
166
|
+
this.player.scriptTag.parentNode.insertBefore(
|
|
167
|
+
this.player.tag,
|
|
168
|
+
this.player.scriptTag
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
this.player.done = false
|
|
172
|
+
this.player.tag.onload = this.onload
|
|
173
|
+
this.player.tag.onreadystatechange = this.onreadystatechange
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
onTimeupdate(e) {
|
|
178
|
+
this.$emit('timeupdate', {
|
|
179
|
+
event: e,
|
|
180
|
+
current_percent: e.percent,
|
|
181
|
+
})
|
|
182
|
+
},
|
|
183
|
+
onLoaded(e) {
|
|
184
|
+
this.$emit('loadeddata', e)
|
|
185
|
+
},
|
|
186
|
+
onPlay(e) {
|
|
187
|
+
this.$emit('play', e)
|
|
188
|
+
},
|
|
189
|
+
onPause(e) {
|
|
190
|
+
this.$emit('pause', e)
|
|
191
|
+
},
|
|
192
|
+
onProgress(e) {
|
|
193
|
+
this.$emit('progress', e)
|
|
194
|
+
},
|
|
195
|
+
onVolumechange(e) {
|
|
196
|
+
this.$emit('volumechange', e)
|
|
197
|
+
},
|
|
198
|
+
onError(e) {
|
|
199
|
+
this.$emit('error', e)
|
|
200
|
+
},
|
|
201
|
+
onEnded(e) {
|
|
202
|
+
this.$emit('ended', e)
|
|
203
|
+
},
|
|
204
|
+
onSeek(e) {
|
|
205
|
+
this.$emit('seeking', e)
|
|
206
|
+
this.$emit('seeked', e)
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
</script>
|
|
211
|
+
|
|
212
|
+
<style scoped>
|
|
213
|
+
.player-skeleton {
|
|
214
|
+
position: relative;
|
|
215
|
+
margin-bottom: -400px;
|
|
216
|
+
height: 400px;
|
|
217
|
+
aspect-ratio: 16/9;
|
|
218
|
+
}
|
|
219
|
+
.player-video {
|
|
220
|
+
min-height: 200px;
|
|
221
|
+
}
|
|
222
|
+
</style>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-container>
|
|
3
|
-
<v-responsive
|
|
3
|
+
<v-responsive>
|
|
4
4
|
<v-skeleton-loader
|
|
5
5
|
v-if="!player.ready"
|
|
6
6
|
class="mx-auto player-skeleton"
|
|
7
7
|
type="image"
|
|
8
8
|
></v-skeleton-loader>
|
|
9
|
-
|
|
10
9
|
<div :id="player.id" :class="playerClass"></div>
|
|
11
10
|
</v-responsive>
|
|
12
11
|
</v-container>
|
|
@@ -31,6 +30,18 @@ export default {
|
|
|
31
30
|
required: true,
|
|
32
31
|
},
|
|
33
32
|
},
|
|
33
|
+
emits: [
|
|
34
|
+
'loadeddata',
|
|
35
|
+
'play',
|
|
36
|
+
'pause',
|
|
37
|
+
'progress',
|
|
38
|
+
'playing',
|
|
39
|
+
'ended',
|
|
40
|
+
'seeking',
|
|
41
|
+
'seeked',
|
|
42
|
+
'timeupdate',
|
|
43
|
+
'error',
|
|
44
|
+
],
|
|
34
45
|
watch: {},
|
|
35
46
|
computed: {
|
|
36
47
|
playerClass() {
|
|
@@ -55,9 +66,19 @@ export default {
|
|
|
55
66
|
loaded: false,
|
|
56
67
|
done: false,
|
|
57
68
|
ready: false,
|
|
69
|
+
currentTime: 0,
|
|
70
|
+
currentPercent: 0,
|
|
58
71
|
},
|
|
59
72
|
}
|
|
60
73
|
},
|
|
74
|
+
mounted() {
|
|
75
|
+
this.init()
|
|
76
|
+
},
|
|
77
|
+
beforeDestroy() {
|
|
78
|
+
if (this.player.ready) {
|
|
79
|
+
window.removeEventListener('message', this.onPostmessage)
|
|
80
|
+
}
|
|
81
|
+
},
|
|
61
82
|
methods: {
|
|
62
83
|
parseVideoSource(src) {
|
|
63
84
|
const result = {
|
|
@@ -71,6 +92,7 @@ export default {
|
|
|
71
92
|
let url = src.sources[0].src
|
|
72
93
|
const regexId =
|
|
73
94
|
/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/
|
|
95
|
+
|
|
74
96
|
const idMatch = url.match(regexId)
|
|
75
97
|
|
|
76
98
|
if (idMatch && idMatch[2].length === 11) {
|
|
@@ -87,7 +109,8 @@ export default {
|
|
|
87
109
|
return result
|
|
88
110
|
}
|
|
89
111
|
},
|
|
90
|
-
onPlayerReady() {
|
|
112
|
+
onPlayerReady(e) {
|
|
113
|
+
this.$emit('loadeddata', e)
|
|
91
114
|
// Uncomment for auto-play
|
|
92
115
|
// e.target.playVideo();
|
|
93
116
|
this.player.ready = true
|
|
@@ -95,10 +118,31 @@ export default {
|
|
|
95
118
|
const source = this.parseVideoSource(this.src)
|
|
96
119
|
|
|
97
120
|
if (source.listId) {
|
|
98
|
-
this.
|
|
121
|
+
this.player.yt.loadPlaylist(source.listId)
|
|
99
122
|
}
|
|
123
|
+
window.addEventListener('message', this.onPostmessage)
|
|
100
124
|
},
|
|
101
125
|
onPlayerStateChange(e) {
|
|
126
|
+
if (e && e.data) {
|
|
127
|
+
switch (e.data) {
|
|
128
|
+
case window.YT.PlayerState.UNSTARTED:
|
|
129
|
+
this.$emit('play', e)
|
|
130
|
+
break
|
|
131
|
+
case window.YT.PlayerState.PAUSED:
|
|
132
|
+
this.$emit('pause', e)
|
|
133
|
+
break
|
|
134
|
+
case window.YT.PlayerState.BUFFERING:
|
|
135
|
+
this.$emit('progress', e)
|
|
136
|
+
break
|
|
137
|
+
case window.YT.PlayerState.PLAYING:
|
|
138
|
+
this.$emit('playing', e)
|
|
139
|
+
break
|
|
140
|
+
case window.YT.PlayerState.ENDED:
|
|
141
|
+
this.$emit('ended', e)
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
102
146
|
if (e.data == window.YT.PlayerState.PLAYING && !this.player.done) {
|
|
103
147
|
setTimeout(() => {
|
|
104
148
|
this.player.yt.stopVideo()
|
|
@@ -106,6 +150,9 @@ export default {
|
|
|
106
150
|
this.player.done = true
|
|
107
151
|
}
|
|
108
152
|
},
|
|
153
|
+
onError(e) {
|
|
154
|
+
this.$emit('error', e)
|
|
155
|
+
},
|
|
109
156
|
tagReady() {
|
|
110
157
|
const source = this.parseVideoSource(this.src)
|
|
111
158
|
|
|
@@ -118,6 +165,7 @@ export default {
|
|
|
118
165
|
events: {
|
|
119
166
|
onReady: this.onPlayerReady,
|
|
120
167
|
onStateChange: this.onPlayerStateChange,
|
|
168
|
+
onError: this.onError,
|
|
121
169
|
},
|
|
122
170
|
})
|
|
123
171
|
},
|
|
@@ -160,9 +208,54 @@ export default {
|
|
|
160
208
|
}
|
|
161
209
|
}
|
|
162
210
|
},
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
211
|
+
onPostmessage(event) {
|
|
212
|
+
// Check that the event was sent from the YouTube IFrame.
|
|
213
|
+
if (event.source === this.player.yt.getIframe().contentWindow) {
|
|
214
|
+
const data = JSON.parse(event.data)
|
|
215
|
+
|
|
216
|
+
// The "infoDelivery" event is used by YT to transmit any
|
|
217
|
+
// kind of information change in the player,
|
|
218
|
+
// such as the current time or a playback quality change.
|
|
219
|
+
if (
|
|
220
|
+
data.event === 'infoDelivery' &&
|
|
221
|
+
data.info &&
|
|
222
|
+
data.info.currentTime
|
|
223
|
+
) {
|
|
224
|
+
// currentTime is emitted very frequently (milliseconds),
|
|
225
|
+
// but we only care about whole second changes.
|
|
226
|
+
const time = Math.floor(data.info.currentTime)
|
|
227
|
+
|
|
228
|
+
if (time !== this.player.currentTime) {
|
|
229
|
+
// Since this postmessage sends multiple times per second there's no reason the
|
|
230
|
+
// current time should be more than a second or two off. If it is then you scrubbed the video
|
|
231
|
+
if (Math.abs(time - this.player.currentTime) > 2) {
|
|
232
|
+
this.$emit('seeking', data)
|
|
233
|
+
this.$emit('seeked', data)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this.player.currentTime = time
|
|
237
|
+
|
|
238
|
+
const totalDuration = Math.floor(
|
|
239
|
+
data.info.progressState &&
|
|
240
|
+
data.info.progressState.duration
|
|
241
|
+
? data.info.progressState.duration
|
|
242
|
+
: this.player.yt.getDuration()
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
this.player.currentPercent =
|
|
246
|
+
totalDuration > 0
|
|
247
|
+
? (this.player.currentTime / totalDuration) *
|
|
248
|
+
100
|
|
249
|
+
: 0
|
|
250
|
+
|
|
251
|
+
this.$emit('timeupdate', {
|
|
252
|
+
event: data,
|
|
253
|
+
current_percent: this.player.currentPercent,
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
166
259
|
},
|
|
167
260
|
}
|
|
168
261
|
</script>
|
|
@@ -172,5 +265,9 @@ export default {
|
|
|
172
265
|
position: relative;
|
|
173
266
|
margin-bottom: -400px;
|
|
174
267
|
height: 400px;
|
|
268
|
+
aspect-ratio: 16/9;
|
|
269
|
+
}
|
|
270
|
+
.player-video {
|
|
271
|
+
min-height: 300px;
|
|
175
272
|
}
|
|
176
273
|
</style>
|
|
@@ -52,11 +52,70 @@
|
|
|
52
52
|
:attributes="current.attributes"
|
|
53
53
|
:src="current.src"
|
|
54
54
|
:elevation="flat ? 0 : elevation"
|
|
55
|
+
@load="$emit('load', $event)"
|
|
56
|
+
@ended="onEnded"
|
|
57
|
+
@loadeddata="onLoadeddata"
|
|
58
|
+
@loadedmetadata="$emit('loadedmetadata', $event)"
|
|
59
|
+
@play="$emit('play', $event)"
|
|
60
|
+
@playing="$emit('playing', $event)"
|
|
61
|
+
@pause="$emit('pause', $event)"
|
|
62
|
+
@seeking="$emit('seeking', $event)"
|
|
63
|
+
@seeked="$emit('seeked', $event)"
|
|
64
|
+
@timeupdate="$emit('timeupdate', $event)"
|
|
65
|
+
@progress="$emit('progress', $event)"
|
|
66
|
+
@volumechange="onVolumeChange"
|
|
67
|
+
@canplay="$emit('canplay', $event)"
|
|
68
|
+
@waiting="$emit('waiting', $event)"
|
|
69
|
+
@canplaythrough="$emit('canplaythrough', $event)"
|
|
70
|
+
@error="$emit('error', $event)"
|
|
71
|
+
@emptied="$emit('emptied', $event)"
|
|
72
|
+
@ratechange="$emit('ratechange', $event)"
|
|
73
|
+
@stalled="$emit('stalled', $event)"
|
|
74
|
+
@abort="$emit('abort', $event)"
|
|
75
|
+
@mouseover="$emit('mouseover', $event)"
|
|
76
|
+
@mouseout="$emit('mouseout', $event)"
|
|
55
77
|
@focusin="onFocusin"
|
|
56
78
|
@focusout="onFocusout"
|
|
57
79
|
@click:fullscreen="onFullscreen"
|
|
58
80
|
></YoutubePlayer>
|
|
59
81
|
|
|
82
|
+
<VimeoPlayer
|
|
83
|
+
ref="vimeoPlayer"
|
|
84
|
+
v-if="
|
|
85
|
+
!loading &&
|
|
86
|
+
parseSourceType(current.src.sources) === 'vimeo'
|
|
87
|
+
"
|
|
88
|
+
:language="language"
|
|
89
|
+
:type="current.type"
|
|
90
|
+
:attributes="current.attributes"
|
|
91
|
+
:src="current.src"
|
|
92
|
+
:elevation="flat ? 0 : elevation"
|
|
93
|
+
@ended="onEnded"
|
|
94
|
+
@loadeddata="onLoadeddata"
|
|
95
|
+
@loadedmetadata="$emit('loadedmetadata', $event)"
|
|
96
|
+
@play="$emit('play', $event)"
|
|
97
|
+
@playing="$emit('playing', $event)"
|
|
98
|
+
@pause="$emit('pause', $event)"
|
|
99
|
+
@seeking="$emit('seeking', $event)"
|
|
100
|
+
@seeked="$emit('seeked', $event)"
|
|
101
|
+
@timeupdate="$emit('timeupdate', $event)"
|
|
102
|
+
@progress="$emit('progress', $event)"
|
|
103
|
+
@volumechange="onVolumeChange"
|
|
104
|
+
@canplay="$emit('canplay', $event)"
|
|
105
|
+
@waiting="$emit('waiting', $event)"
|
|
106
|
+
@canplaythrough="$emit('canplaythrough', $event)"
|
|
107
|
+
@error="$emit('error', $event)"
|
|
108
|
+
@emptied="$emit('emptied', $event)"
|
|
109
|
+
@ratechange="$emit('ratechange', $event)"
|
|
110
|
+
@stalled="$emit('stalled', $event)"
|
|
111
|
+
@abort="$emit('abort', $event)"
|
|
112
|
+
@mouseover="$emit('mouseover', $event)"
|
|
113
|
+
@mouseout="$emit('mouseout', $event)"
|
|
114
|
+
@focusin="onFocusin"
|
|
115
|
+
@focusout="onFocusout"
|
|
116
|
+
@click:fullscreen="onFullscreen"
|
|
117
|
+
></VimeoPlayer>
|
|
118
|
+
|
|
60
119
|
<Html5Player
|
|
61
120
|
ref="html5Player"
|
|
62
121
|
v-if="
|
|
@@ -82,8 +141,10 @@
|
|
|
82
141
|
@loadeddata="onLoadeddata"
|
|
83
142
|
@loadedmetadata="$emit('loadedmetadata', $event)"
|
|
84
143
|
@play="$emit('play', $event)"
|
|
144
|
+
@playing="$emit('playing', $event)"
|
|
85
145
|
@pause="$emit('pause', $event)"
|
|
86
146
|
@seeking="$emit('seeking', $event)"
|
|
147
|
+
@seeked="$emit('seeked', $event)"
|
|
87
148
|
@timeupdate="$emit('timeupdate', $event)"
|
|
88
149
|
@progress="$emit('progress', $event)"
|
|
89
150
|
@volumechange="onVolumeChange"
|
|
@@ -135,6 +196,7 @@
|
|
|
135
196
|
<script>
|
|
136
197
|
import { t } from '../i18n/i18n'
|
|
137
198
|
import YoutubePlayer from './Media/YoutubePlayer.vue'
|
|
199
|
+
import VimeoPlayer from './Media/VimeoPlayer.vue'
|
|
138
200
|
import Html5Player from './Media/Html5Player.vue'
|
|
139
201
|
import PlaylistMenu from './Media/PlaylistMenu.vue'
|
|
140
202
|
|
|
@@ -142,6 +204,7 @@ export default {
|
|
|
142
204
|
name: 'VuetifyPlayer',
|
|
143
205
|
components: {
|
|
144
206
|
YoutubePlayer,
|
|
207
|
+
VimeoPlayer,
|
|
145
208
|
Html5Player,
|
|
146
209
|
PlaylistMenu,
|
|
147
210
|
},
|
|
@@ -249,8 +312,10 @@ export default {
|
|
|
249
312
|
'loadeddata',
|
|
250
313
|
'loadedmetadata',
|
|
251
314
|
'play',
|
|
315
|
+
'playing',
|
|
252
316
|
'pause',
|
|
253
317
|
'seeking',
|
|
318
|
+
'seeked',
|
|
254
319
|
'timeupdate',
|
|
255
320
|
'progress',
|
|
256
321
|
'volumechange',
|
|
@@ -293,6 +358,10 @@ export default {
|
|
|
293
358
|
player() {
|
|
294
359
|
if (this.parseSourceType(this.current.src.sources) === 'youtube') {
|
|
295
360
|
return this.$refs.youtubePlayer
|
|
361
|
+
} else if (
|
|
362
|
+
this.parseSourceType(this.current.src.sources) === 'vimeo'
|
|
363
|
+
) {
|
|
364
|
+
return this.$refs.vimeoPlayer
|
|
296
365
|
} else if (
|
|
297
366
|
this.parseSourceType(this.current.src.sources) === 'html5'
|
|
298
367
|
) {
|
|
@@ -514,6 +583,9 @@ export default {
|
|
|
514
583
|
const ytRegex =
|
|
515
584
|
/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/
|
|
516
585
|
|
|
586
|
+
const vimeoRegex =
|
|
587
|
+
/(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|video\/|)(\d+)(?:|\/\?)/
|
|
588
|
+
|
|
517
589
|
if (!sources || !sources.length || !sources[0].src) {
|
|
518
590
|
return null
|
|
519
591
|
}
|
|
@@ -526,6 +598,8 @@ export default {
|
|
|
526
598
|
return null
|
|
527
599
|
} else if (src.match(ytRegex) || type === 'video/youtube') {
|
|
528
600
|
return 'youtube'
|
|
601
|
+
} else if (src.match(vimeoRegex) || type === 'video/vimeo') {
|
|
602
|
+
return 'vimeo'
|
|
529
603
|
} else {
|
|
530
604
|
return 'html5'
|
|
531
605
|
}
|