Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #207 from WordPress/active_media
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvkb authored Sep 16, 2021
2 parents e27829c + c08436f commit b69efbd
Show file tree
Hide file tree
Showing 27 changed files with 1,061 additions and 276 deletions.
5 changes: 5 additions & 0 deletions src/assets/licenses/by.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/cc-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/cc0.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/nc.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/nd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/pdm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/licenses/sa.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
190 changes: 190 additions & 0 deletions src/components/AudioTrack/AudioController.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<template>
<div class="audio-controller">
<Waveform
:class="waveformClasses"
:message="message ? $t(`audio-track.messages.${message}`) : null"
:current-time="currentTime"
:duration="duration"
:peaks="audio.peaks"
@seeked="handleSeeked"
/>

<!-- eslint-disable vuejs-accessibility/media-has-caption -->
<audio
v-show="false"
v-bind="$attrs"
:id="audio.id"
ref="audioEl"
class="audio-controller"
controls
:src="audio.url"
crossorigin="anonymous"
@loadedmetadata="handleReady"
@error="handleError"
/>
<!-- eslint-enable vuejs-accessibility/media-has-caption -->
</div>
</template>

<script>
import Waveform from '~/components/AudioTrack/Waveform'
import { computed, ref, useStore, watch } from '@nuxtjs/composition-api'
import {
SET_ACTIVE_MEDIA_ITEM,
UNSET_ACTIVE_MEDIA_ITEM,
} from '~/store-modules/mutation-types'
/**
* Controls the interaction between the parent Vue component, the underlying
* HTMLAudioElement and the Active Media Store. Also displays the waveform that
* is deeply linked to timekeeping for the HTMLAudioElement.
*/
export default {
name: 'AudioController',
components: { Waveform },
inheritAttrs: false,
model: {
prop: 'status',
event: 'change',
},
props: {
/**
* the information about the track, typically from a track's detail endpoint
*/
audio: {
type: Object,
required: true,
},
/**
* the playing/paused status of the audio
*/
status: {
type: String,
required: true,
validator: (val) => ['playing', 'paused'].includes(val),
},
/**
* the CSS classes to apply on the waveform; This can take any form
* acceptable to Vue class bindings.
*/
waveformClasses: {},
},
setup(props, { emit }) {
const store = useStore()
const audioEl = ref(null) // template ref
/* Status */
const isActiveTrack = computed(
() =>
store.state.activeMediaType === 'audio' &&
store.state.activeMediaId === props.audio.id
)
// Sync status from parent to player and store
watch(
() => props.status,
(status) => {
if (!audioEl.value) return
switch (status) {
case 'playing':
audioEl.value.play()
store.commit(SET_ACTIVE_MEDIA_ITEM, {
type: 'audio',
id: props.audio.id,
})
window.requestAnimationFrame(updateTimeLoop)
break
case 'paused':
audioEl.value.pause()
if (isActiveTrack.value) {
store.commit(UNSET_ACTIVE_MEDIA_ITEM)
}
break
}
}
)
// Sync status from store to parent
watch(
() => [store.state.activeMediaType, store.state.activeMediaId],
() => {
const status = isActiveTrack.value ? 'playing' : 'paused'
emit('change', status)
}
)
/* Error handling */
const message = ref('loading')
const handleError = (event) => {
const error = event.target.error
let errorMsg
switch (error.code) {
case error.MEDIA_ERR_ABORTED:
errorMsg = 'err_aborted'
break
case error.MEDIA_ERR_NETWORK:
errorMsg = 'err_network'
break
case error.MEDIA_ERR_DECODE:
errorMsg = 'err_decode'
break
case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
errorMsg = 'err_unsupported'
break
}
message.value = errorMsg
}
/* Timekeeping */
const currentTime = ref(0)
const duration = ref(0)
const updateTime = () => {
if (!audioEl.value) return
currentTime.value = audioEl.value.currentTime
duration.value = audioEl.value.duration
}
const updateTimeLoop = () => {
updateTime()
if (props.status === 'playing') {
// Audio is playing, keep looping
window.requestAnimationFrame(updateTimeLoop)
}
}
/* Metadata readiness */
const handleReady = () => {
message.value = null
updateTime()
emit('ready')
}
/* Seeking */
const handleSeeked = (frac) => {
if (audioEl.value && duration.value) {
audioEl.value.currentTime = duration.value * frac
updateTime()
}
}
return {
audioEl,
message,
handleError,
currentTime,
duration,
handleReady,
handleSeeked,
}
},
}
</script>
16 changes: 16 additions & 0 deletions src/components/AudioTrack/AudioThumbnail.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<!-- Should be wrapped by a fixed-width parent -->
<div class="h-0 w-full pt-full bg-yellow">&nbsp;</div>
</template>

<script>
export default {
name: 'AudioThumbnail',
props: {
audio: {
type: Object,
required: true,
},
},
}
</script>
Loading

0 comments on commit b69efbd

Please sign in to comment.