mastoradio-fork/src/components/YoutubePlayer.svelte

153 lines
3.5 KiB
Svelte
Raw Normal View History

2020-01-18 17:42:44 +01:00
<div bind:this={element}></div>
<script>
2020-02-24 23:18:51 +01:00
import { createEventDispatcher, onMount, onDestroy } from 'svelte'
2021-11-07 00:11:15 +01:00
import { loadIframeApi, STATE } from '/src/services/youtube.js'
import { queue } from '/src/services/misc.js'
2020-01-18 17:42:44 +01:00
// input props
export let id
export let paused
export let volume
2020-02-29 02:39:31 +01:00
let element
let player
let animationFrameId
let loaded = false
let currentTime = null
let duration = null
2020-02-24 23:18:51 +01:00
const dispatch = createEventDispatcher()
2020-01-18 17:42:44 +01:00
$: load(id)
2020-02-24 23:18:51 +01:00
$: paused ? pause() : play()
2020-01-18 17:42:44 +01:00
$: setVolume(volume)
2020-02-24 23:18:51 +01:00
$: dispatch('timeupdate', currentTime)
$: dispatch('durationchange', duration)
2020-01-18 17:42:44 +01:00
const { enqueue, run } = queue()
export const load = (id) => enqueue((player) => {
2020-02-29 02:39:31 +01:00
loaded = false
2020-01-18 17:42:44 +01:00
currentTime = null
duration = null
2020-02-29 02:39:31 +01:00
dispatch('loadstart')
2020-02-24 23:18:51 +01:00
player.cueVideoById(id)
2020-01-18 17:42:44 +01:00
})
2020-02-24 23:18:51 +01:00
export const play = () => enqueue((player) => {
player.playVideo()
})
export const pause = () => enqueue((player) => {
player.pauseVideo()
2020-01-18 17:42:44 +01:00
})
const setVolume = volume => enqueue(player => {
player.setVolume(volume)
})
export const seek = (seconds, allowSeekAhead) => enqueue((player) => {
player.seekTo(seconds, allowSeekAhead)
})
2020-02-24 23:18:51 +01:00
onMount(async () => {
const api = await loadIframeApi()
2020-01-18 17:42:44 +01:00
2020-02-24 23:18:51 +01:00
element.id = Math.random().toString(16).slice(2, 8)
2020-02-21 23:32:04 +01:00
2020-02-24 23:18:51 +01:00
const onReady = ({ target: player }) => {
if (player.isMuted()) {
player.unMute()
2020-01-18 17:42:44 +01:00
}
2020-02-24 23:18:51 +01:00
run(player)
}
2020-01-18 17:42:44 +01:00
2020-02-24 23:18:51 +01:00
const onStateChange = ({ data: state, target: player }) => {
switch (state) {
case STATE.UNSTARTED:
break
2020-01-20 03:26:18 +01:00
2020-02-24 23:18:51 +01:00
case STATE.ENDED:
dispatch('ended')
break
2020-01-18 17:42:44 +01:00
2020-02-24 23:18:51 +01:00
case STATE.PLAYING:
const newDuration = player.getDuration()
if (duration !== newDuration) {
duration = newDuration
2020-02-29 02:39:31 +01:00
}
if (loaded) {
dispatch('play')
2020-01-20 03:26:18 +01:00
}
2020-02-24 23:18:51 +01:00
break
case STATE.PAUSED:
2020-02-29 02:39:31 +01:00
if (loaded) {
dispatch('pause')
}
2020-02-24 23:18:51 +01:00
break
case STATE.CUED:
2020-02-29 02:39:31 +01:00
if (!loaded) {
loaded = true
}
2021-11-06 22:43:43 +01:00
if (!paused) {
player.playVideo()
}
2020-02-24 23:18:51 +01:00
dispatch('canplay')
break
}
if (state === STATE.PLAYING) {
const step = () => {
currentTime = player.getCurrentTime()
2020-01-20 03:26:18 +01:00
animationFrameId = requestAnimationFrame(step)
}
2020-01-18 17:42:44 +01:00
2020-02-24 23:18:51 +01:00
step()
} else {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId)
}
2020-01-18 17:42:44 +01:00
}
2020-02-24 23:18:51 +01:00
}
2020-01-18 17:42:44 +01:00
2020-02-24 23:18:51 +01:00
const onError = error => {
dispatch('error', error)
}
player = new api.Player(element.id, {
playerVars: {
autoplay: 0,
controls: 0,
enablejsapi: 1,
modestbranding: 1,
rel: 0
},
events: {
onReady,
onStateChange,
onError
}
2020-01-18 17:42:44 +01:00
})
})
onDestroy(() => {
if (player) {
player.destroy()
}
})
2021-11-06 22:43:43 +01:00
</script>