CellVideo.vue 5.64 KB
Newer Older
Anton's avatar
Intial  
Anton committed
1
2
<template lang="pug">

Anton's avatar
Anton committed
3
  div(v-if="visible", :class="{'display-preview': preview, 'display-full': display}")
Anton's avatar
Anton committed
4
    q-window-resize-observable(@resize="resizeVideo")
Anton's avatar
Intial  
Anton committed
5
6
    template(v-if="display")
      video-player(
7
      :class="{ hidePlayer: !showPlayer }",
8
      ref='videoPlayer',
9
      :annotation="video || fauxVideo",
Anton's avatar
Anton committed
10
11
      @ready="handlePlayerReady",
      @play="handlePlayerPlaying",
12
      @canplay:once="onCanPlay",
Anton's avatar
Anton committed
13
      @time="handlePlayerTimeChange",
Anton's avatar
Anton committed
14
15
      :no-fullscreen="true",
      :no-volume-panel="true")
Anton's avatar
Intial  
Anton committed
16
17

    template(v-else)
Anton's avatar
Anton committed
18
      cell-info(:cell="cell", type="Video Cell")
Anton's avatar
Intial  
Anton committed
19
20
21
22

</template>

<script>
Anton's avatar
Anton committed
23
  import CellInfo from '../CellInfo'
Anton's avatar
Intial  
Anton committed
24
  import { VideoPlayer } from '../../../shared'
25
  import { DateTime, Interval } from 'luxon'
Anton's avatar
Intial  
Anton committed
26
27
28

  export default {
    components: {
Anton's avatar
Anton committed
29
      CellInfo,
Anton's avatar
Intial  
Anton committed
30
31
      VideoPlayer
    },
32
    props: ['cell', 'display', 'preview', 'visible'],
Anton's avatar
Intial  
Anton committed
33
34
    data () {
      return {
35
        video: undefined,
36
        videoTime: undefined,
Anton's avatar
Anton committed
37
        contextTime: undefined,
38
39
        player: {},
        showPlayer: false
Anton's avatar
Intial  
Anton committed
40
41
42
43
      }
    },
    computed: {
      fauxVideo () {
Anton's avatar
Anton committed
44
        return {
45
46
47
48
          body: {
            type: 'Video',
            purpose: 'linking',
            source: {
Anton's avatar
Anton committed
49
              id: this.cell ? this.cell.data.content : undefined
50
51
            }
          }
Anton's avatar
Intial  
Anton committed
52
53
54
        }
      }
    },
55
56
57
    watch: {
      visible (val) {
        if (!val && this.player) {
Anton's avatar
Anton committed
58
59
60
61
62
63
          try {
            this.player.pause()
          }
          catch (err) {
            console.debug('Player pause failed', err)
          }
64
65
66
        }
      }
    },
Anton's avatar
Anton committed
67
    async mounted () {
Anton's avatar
Anton committed
68
      if (this.cell && this.cell.data.sourceUuid) {
Anton's avatar
Anton committed
69
        this.video = await this.$store.dispatch('annotations/get', this.cell.data.id)
Anton's avatar
Anton committed
70
71
        if (this.video) {
          this.videoTime = DateTime.fromMillis(this.video.target.selector._valueMillis)
Anton's avatar
Anton committed
72
73
          this.contextTime = this.videoTime
        }
Anton's avatar
Intial  
Anton committed
74
      }
75
      if (this.display) {
Anton's avatar
Anton committed
76
        if (!this.cell.config.start) this.showPlayer = true
77
        else {
Anton's avatar
Anton committed
78
          // FIXME: replace timeout with more efficient solution
79
          const _this = this
Anton's avatar
Anton committed
80
          // Show the player after 2s if the canPlay event does not fire
81
82
          setTimeout(() => { _this.showPlayer = true }, 2000)
        }
Anton's avatar
Anton committed
83
        const _this = this
84
85
        this.$root.$on('grid-datetime', datetime => {
          console.debug('CellVideo: received grid-datetime', datetime.toISO())
Anton's avatar
Anton committed
86
87
88
          _this.setPlayerTimeFromDateTime(datetime)
        })
        this.$root.$on('annotation-trigger', (annotation, annotationGlobalTime) => {
89
          if (!_this.video) return
Anton's avatar
Anton committed
90
          if (_this.video.target && annotation.target.id === _this.video.target.id) {
91
            console.debug('CellVideo: received annotation-trigger', annotation.id, annotationGlobalTime.toISO())
Anton's avatar
Anton committed
92
            _this.setPlayerTimeFromDateTime(annotationGlobalTime)
Anton's avatar
Intial  
Anton committed
93
94
95
96
97
          }
        })
      }
    },
    methods: {
98
      onCanPlay () {
Anton's avatar
Anton committed
99
        if (this.cell && this.cell.config.start) {
100
          if (this.player) {
Anton's avatar
Anton committed
101
            this.player.currentTime(this.cell.config.start)
102
            this.showPlayer = true
103
104
105
          }
        }
      },
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
      resizeVideo () {
        if (this.$refs) {
          let player = this.$refs.videoPlayer
          if (player) {
            let video = player.$el.querySelector('.vjs-tech')
            if (video) {
              let pw = video.clientWidth
              let cw = this.$el.clientWidth
              if (cw > pw) {
                video.style.width = '100%'
                video.style.height = 'auto'
              }
              else {
                video.style.height = '100%'
                video.style.width = 'auto'
              }
            }
          }
        }
      },
Anton's avatar
Intial  
Anton committed
126
127
      getSignature () {
        if (this.video) {
Anton's avatar
Anton committed
128
          return { origin: this.video, type: 'Video' }
Anton's avatar
Intial  
Anton committed
129
130
        }
        else {
Anton's avatar
Anton committed
131
          return { origin: this.cell, type: '2DCell' }
Anton's avatar
Intial  
Anton committed
132
133
        }
      },
Anton's avatar
Anton committed
134
      setPlayerTimeFromDateTime (datetime) {
135
        if (!this.visible) return
Anton's avatar
Anton committed
136
        if (this.player && this.videoTime) {
137
138
139
140
141
142
143
144
145
146
          try {
            const movieTime = Interval.fromDateTimes(this.videoTime, datetime)
              .toDuration()
              .as('seconds')
            console.debug('CellVideo: setting player to second', movieTime)
            this.player.currentTime(movieTime)
          }
          catch (e) {
            console.debug('Failed to set time', e.message)
          }
Anton's avatar
Anton committed
147
148
        }
      },
Anton's avatar
Intial  
Anton committed
149
      handlePlayerReady (player) {
Anton's avatar
Anton committed
150
        this.$root.$emit('video-loaded', this.getSignature())
Anton's avatar
Intial  
Anton committed
151
        this.player = player
152
        this.resizeVideo()
Anton's avatar
Intial  
Anton committed
153
154
      },
      handlePlayerPlaying () {
Anton's avatar
Anton committed
155
        this.$root.$emit('video-started-playing', this.getSignature())
Anton's avatar
Intial  
Anton committed
156
157
      },
      handlePlayerTimeChange (localTime) {
158
        if (!this.visible) return
Anton's avatar
Anton committed
159
160
161
162
163
164
165
        if (this.cell) {
          const { start, duration } = this.cell.config
          if (start && localTime < start) return this.player.currentTime(start)
          if (duration && localTime > start + duration) {
            this.player.pause()
            return this.player.currentTime(start + duration)
          }
166
        }
167
        let globalTime = DateTime.local()
Anton's avatar
Anton committed
168
        if (this.videoTime) globalTime = this.videoTime.plus(localTime * 1000.0)
Anton's avatar
Anton committed
169
        this.$root.$emit('video-time-changed', localTime, globalTime, this.getSignature())
Anton's avatar
Intial  
Anton committed
170
171
172
173
174
175
176
177
      }
    }
  }
</script>

<style scoped lang="stylus">

  div.display-full
178
    background-color #252525
Anton's avatar
Intial  
Anton committed
179
180
181
182
183

  div.display-preview
    padding 1em
    color #666

Anton Koch's avatar
Anton Koch committed
184
185
186
  .video-js.vjs-paused .vjs-big-play-button
    background black

Mathias Bär's avatar
Mathias Bär committed
187
188
189
190
  .video-js .vjs-tech
    border-right: 1px solid #111 !important
    border-bottom: 1px solid #111 !important

191
192
193
  .cell-type-video
    height 100%

194
195
196
  .hidePlayer
    visibility: hidden

Anton's avatar
Intial  
Anton committed
197
</style>