CellVideo.vue 5.32 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}")
4
    q-window-resize-observable(@resize="onResize")
Anton's avatar
Intial  
Anton committed
5 6
    template(v-if="display")
      video-player(
7
      ref='videoPlayer',
8
      :annotation="video || fauxVideo",
Anton's avatar
Anton committed
9 10
      @ready="handlePlayerReady",
      @play="handlePlayerPlaying",
11
      @canplay:once="onCanPlay",
Anton's avatar
Anton committed
12
      @time="handlePlayerTimeChange",
Anton's avatar
Anton committed
13
      :no-fullscreen="true")
Anton's avatar
Intial  
Anton committed
14 15

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

</template>

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

  export default {
    components: {
Anton's avatar
Anton committed
27
      CellInfo,
Anton's avatar
Intial  
Anton committed
28 29
      VideoPlayer
    },
30
    props: ['cell', 'display', 'preview', 'visible'],
Anton's avatar
Intial  
Anton committed
31 32
    data () {
      return {
33
        video: undefined,
34
        videoTime: undefined,
Anton's avatar
Anton committed
35
        contextTime: undefined,
Anton's avatar
Intial  
Anton committed
36 37 38 39 40
        player: {}
      }
    },
    computed: {
      fauxVideo () {
Anton's avatar
Anton committed
41
        return {
42 43 44 45 46 47 48
          body: {
            type: 'Video',
            purpose: 'linking',
            source: {
              id: this.cell['content']
            }
          }
Anton's avatar
Intial  
Anton committed
49 50 51
        }
      }
    },
52 53 54
    watch: {
      visible (val) {
        if (!val && this.player) {
Anton's avatar
Anton committed
55 56 57 58 59 60
          try {
            this.player.pause()
          }
          catch (err) {
            console.debug('Player pause failed', err)
          }
61 62 63
        }
      }
    },
Anton's avatar
Anton committed
64
    async mounted () {
Anton's avatar
Intial  
Anton committed
65
      if (this.cell.sourceUuid) {
Anton's avatar
Anton committed
66 67 68 69 70 71 72 73 74
        const
          result = await this.$store.dispatch('annotations/find', { uuid: this.cell.sourceUuid }),
          video = result.items.shift()

        if (video) {
          this.video = video
          this.videoTime = DateTime.fromISO(video.target.selector.value)
          this.contextTime = this.videoTime
        }
Anton's avatar
Intial  
Anton committed
75
      }
76
      if (this.display) {
Anton's avatar
Anton committed
77
        const _this = this
78 79
        this.$root.$on('grid-datetime', datetime => {
          console.debug('CellVideo: received grid-datetime', datetime.toISO())
Anton's avatar
Anton committed
80 81 82
          _this.setPlayerTimeFromDateTime(datetime)
        })
        this.$root.$on('annotation-trigger', (annotation, annotationGlobalTime) => {
83
          if (!_this.video) return
Anton's avatar
Anton committed
84 85 86
          if (_this.video.target && annotation.target.id === _this.video.target.id) {
            console.debug('CellVideo: received annotation-trigger', annotation.uuid, annotationGlobalTime.toISO())
            _this.setPlayerTimeFromDateTime(annotationGlobalTime)
Anton's avatar
Intial  
Anton committed
87 88 89 90 91
          }
        })
      }
    },
    methods: {
92 93 94 95 96 97 98
      onCanPlay () {
        if (this.cell.start) {
          if (this.player) {
            this.player.currentTime(this.cell.start)
          }
        }
      },
99 100 101 102 103
      onResize () {
        this.resizeVideo()
      },
      resizeVideo () {
        if (this.$refs) {
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
          // TODO: fix scaling issues with youtube
          // 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'
          //     }
          //   }
          // }
121 122
        }
      },
Anton's avatar
Intial  
Anton committed
123 124
      getSignature () {
        if (this.video) {
Anton's avatar
Anton committed
125
          return { origin: this.video, type: 'Video' }
Anton's avatar
Intial  
Anton committed
126 127
        }
        else {
Anton's avatar
Anton committed
128
          return { origin: this.cell, type: '2DCell' }
Anton's avatar
Intial  
Anton committed
129 130
        }
      },
Anton's avatar
Anton committed
131
      setPlayerTimeFromDateTime (datetime) {
132
        if (!this.visible) return
Anton's avatar
Anton committed
133
        if (this.player && this.videoTime) {
134 135 136 137 138 139 140 141 142 143
          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
144 145
        }
      },
Anton's avatar
Intial  
Anton committed
146
      handlePlayerReady (player) {
Anton's avatar
Anton committed
147
        this.$root.$emit('video-loaded', this.getSignature())
Anton's avatar
Intial  
Anton committed
148
        this.player = player
149
        this.resizeVideo()
Anton's avatar
Intial  
Anton committed
150 151
      },
      handlePlayerPlaying () {
Anton's avatar
Anton committed
152
        this.$root.$emit('video-started-playing', this.getSignature())
Anton's avatar
Intial  
Anton committed
153 154
      },
      handlePlayerTimeChange (localTime) {
155
        if (!this.visible) return
156 157 158 159 160
        if (this.cell.start && localTime < this.cell.start) return this.player.currentTime(this.cell.start)
        if (this.cell.duration && localTime > this.cell.start + this.cell.duration) {
          this.player.pause()
          return this.player.currentTime(this.cell.start + this.cell.duration)
        }
161
        let globalTime = DateTime.local()
Anton's avatar
Intial  
Anton committed
162
        if (this.videoTime) {
163
          globalTime = this.videoTime.plus(localTime * 1000.0)
Anton's avatar
Intial  
Anton committed
164
        }
Anton's avatar
Anton committed
165
        this.$root.$emit('video-time-changed', localTime, globalTime, this.getSignature())
Anton's avatar
Intial  
Anton committed
166 167 168 169 170 171 172 173
      }
    }
  }
</script>

<style scoped lang="stylus">

  div.display-full
174
    background-color #252525
Anton's avatar
Intial  
Anton committed
175 176 177 178 179

  div.display-preview
    padding 1em
    color #666

Anton Koch's avatar
Anton Koch committed
180 181 182
  .video-js.vjs-paused .vjs-big-play-button
    background black

Mathias Bär's avatar
Mathias Bär committed
183 184 185 186
  .video-js .vjs-tech
    border-right: 1px solid #111 !important
    border-bottom: 1px solid #111 !important

187 188 189
  .cell-type-video
    height 100%

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