clappr-chromecast-plugin
Version:
Chromecast support for Clappr
140 lines (117 loc) • 4.09 kB
JavaScript
import {Events, Log, Playback, template} from 'clappr'
import chromecastHTML from './public/chromecast.html'
const TICK_INTERVAL = 100
export default class ChromecastPlayback extends Playback {
get name() { return 'chromecast_playback' }
get template() { return template(chromecastHTML) }
get attributes() { return { class: 'chromecast-playback' } }
get isReady() { return true }
constructor(options) {
super(options)
this.src = options.src
this.currentMedia = options.currentMedia
this.mediaControl = options.mediaControl
this.currentMedia.addUpdateListener(() => this.onMediaStatusUpdate())
this.settings = options.settings
let noVolume = (name) => name != 'volume'
this.settings.default && (this.settings.default = this.settings.default.filter(noVolume))
this.settings.left && (this.settings.left = this.settings.left.filter(noVolume))
this.settings.right && (this.settings.right = this.settings.right.filter(noVolume))
}
render() {
let template = this.template()
this.$el.html(template)
if (this.options.poster) {
this.$('.chromecast-playback-background').css('background-image', 'url(' + this.options.poster + ')')
} else {
this.$('.chromecast-playback-background').css('background-color', '#666')
}
}
play() {
this.currentMedia.play()
}
pause() {
this.stopTimer()
this.currentMedia.pause()
if (this.getPlaybackType() === Playback.LIVE) {
this.trigger(Events.PLAYBACK_DVR, true)
}
}
stop() {
this.stopTimer()
this.currentMedia.pause() // FIXME: properly handle media stop
}
seek(time) {
this.stopTimer()
let request = new chrome.cast.media.SeekRequest()
request.currentTime = time
this.currentMedia.seek(request,
() => this.startTimer(), () => Log.warn('seek failed'))
if (this.getPlaybackType() === Playback.LIVE) {
// assume live if time within 30 seconds of end of live stream
this.trigger(Events.PLAYBACK_DVR, time < this.getDuration() - 30)
}
}
seekPercentage(percentage) {
if (percentage >= 0 && percentage <= 100) {
let duration = this.getDuration()
this.seek(percentage * duration / 100)
}
}
startTimer() {
this.timer = setInterval(() => this.updateMediaControl(), TICK_INTERVAL)
}
stopTimer() {
clearInterval(this.timer)
this.timer = null
}
getDuration() {
return this.currentMedia.media.duration
}
isPlaying() {
return this.currentMedia.playerState === 'PLAYING' || this.currentMedia.playerState === 'BUFFERING'
}
getPlaybackType() {
return !!this.currentMedia.liveSeekableRange ? Playback.LIVE : Playback.VOD
}
onMediaStatusUpdate() {
this.mediaControl.changeTogglePlay()
if (this.isPlaying() && !this.timer) {
this.startTimer()
}
if (this.currentMedia.playerState === 'BUFFERING') {
this.isBuffering = true
this.trigger(Events.PLAYBACK_BUFFERING, this.name)
} else if (this.currentMedia.playerState === 'PLAYING') {
if (this.isBuffering) {
this.isBuffering = false
this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
}
if (this.prevState !== this.currentMedia.playerState) {
this.trigger(Events.PLAYBACK_PLAY, this.name)
}
} else if (this.currentMedia.playerState === 'IDLE') {
if (this.isBuffering) {
this.isBuffering = false
this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
}
this.trigger(Events.PLAYBACK_ENDED, this.name)
} else if (this.currentMedia.playerState === 'PAUSED') {
if (this.prevState !== this.currentMedia.playerState) {
this.trigger(Events.PLAYBACK_PAUSE, this.name)
}
}
this.prevState = this.currentMedia.playerState
}
updateMediaControl() {
let position = this.currentMedia.getEstimatedTime()
let duration = this.currentMedia.media.duration
this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: position, total: duration}, this.name)
}
show() {
this.$el.show()
}
hide() {
this.$el.hide()
}
}