update youtube player bindings
This commit is contained in:
parent
4263abe3e4
commit
656d250852
@ -2,16 +2,18 @@
|
|||||||
<div class="playerBig__player" class:placeholder={!ready} class:hidden={!large}>
|
<div class="playerBig__player" class:placeholder={!ready} class:hidden={!large}>
|
||||||
{#if $current}
|
{#if $current}
|
||||||
<YoutubePlayer
|
<YoutubePlayer
|
||||||
id={$current ? $current.media.credentials.id : null}
|
bind:this={player}
|
||||||
|
id={$current.media.credentials.id}
|
||||||
class="playerBig__iframe"
|
class="playerBig__iframe"
|
||||||
paused={$paused}
|
paused={$paused}
|
||||||
volume={$volume}
|
volume={$volume}
|
||||||
bind:ready
|
on:canplay={onCanPlay}
|
||||||
bind:ended
|
on:play={onPlay}
|
||||||
bind:error
|
on:pause={onPause}
|
||||||
bind:currentTime
|
on:timeupdate={onTimeUpdate}
|
||||||
bind:duration
|
on:durationchange={onDurationChange}
|
||||||
bind:seek={seek}
|
on:ended={onEnded}
|
||||||
|
on:error={onError}
|
||||||
></YoutubePlayer>
|
></YoutubePlayer>
|
||||||
<div class="playerBig__overlay" on:click={() => $paused = !$paused}></div>
|
<div class="playerBig__overlay" on:click={() => $paused = !$paused}></div>
|
||||||
<button
|
<button
|
||||||
@ -28,7 +30,7 @@
|
|||||||
{#if $current}
|
{#if $current}
|
||||||
<img
|
<img
|
||||||
class="playerCover__img"
|
class="playerCover__img"
|
||||||
src={'https://img.youtube.com/vi/' + $current.media.credentials.id + '/mqdefault.jpg'}
|
src={$current.media.cover}
|
||||||
alt="cover"
|
alt="cover"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@ -42,11 +44,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Progress
|
<Progress
|
||||||
duration={duration}
|
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
|
duration={duration}
|
||||||
ready={ready}
|
ready={ready}
|
||||||
on:input={event => updateCurrentTime(event.target.value, false)}
|
on:input={event => seek(event.target.value, true)}
|
||||||
on:change={event => updateCurrentTime(event.target.value, true)}
|
on:change={event => seek(event.target.value, true)}
|
||||||
></Progress>
|
></Progress>
|
||||||
|
|
||||||
<div class="playerTrack">
|
<div class="playerTrack">
|
||||||
@ -81,8 +83,8 @@
|
|||||||
duration={duration}
|
duration={duration}
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
ready={ready}
|
ready={ready}
|
||||||
on:input={event => updateCurrentTime(event.target.value, false)}
|
on:input={event => seek(event.target.value, true)}
|
||||||
on:change={event => updateCurrentTime(event.target.value, true)}
|
on:change={event => seek(event.target.value, true)}
|
||||||
></Progress>
|
></Progress>
|
||||||
<div class="playerSticky__referer">shared by <span class="playerTrack__username">{$current.referer.username}</div>
|
<div class="playerSticky__referer">shared by <span class="playerTrack__username">{$current.referer.username}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -103,6 +105,8 @@
|
|||||||
export let large
|
export let large
|
||||||
export let sticky
|
export let sticky
|
||||||
|
|
||||||
|
let player
|
||||||
|
|
||||||
const paused = getContext('paused')
|
const paused = getContext('paused')
|
||||||
const volume = getContext('volume')
|
const volume = getContext('volume')
|
||||||
const current = getContext('current')
|
const current = getContext('current')
|
||||||
@ -110,23 +114,43 @@
|
|||||||
const selectNext = getContext('selectNext')
|
const selectNext = getContext('selectNext')
|
||||||
|
|
||||||
let ready = null
|
let ready = null
|
||||||
let ended = null
|
|
||||||
let error = null
|
|
||||||
let currentTime = null
|
let currentTime = null
|
||||||
let duration = null
|
let duration = null
|
||||||
let seek = null
|
|
||||||
|
|
||||||
$: if (ended || error) {
|
const onCanPlay = () => {
|
||||||
|
ready = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPlay = () => {
|
||||||
|
$paused = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPause = () => {
|
||||||
|
$paused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTimeUpdate = event => {
|
||||||
|
currentTime = event.detail
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDurationChange = event => {
|
||||||
|
duration = event.detail
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEnded = () => {
|
||||||
selectNext()
|
selectNext()
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateCurrentTime = (seconds, seekAhead) => {
|
const onError = event => {
|
||||||
seek(seconds, seekAhead)
|
console.error(event.detail)
|
||||||
currentTime = seconds
|
selectNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
const seek = (seconds, seekAhead) => {
|
||||||
|
player.seek(seconds, seekAhead)
|
||||||
}
|
}
|
||||||
|
|
||||||
const switchBigPlayer = () => {
|
const switchBigPlayer = () => {
|
||||||
large = !large
|
large = !large
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div bind:this={element}></div>
|
<div bind:this={element}></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount, onDestroy } from 'svelte'
|
import { createEventDispatcher, onMount, onDestroy } from 'svelte'
|
||||||
import { loadIframeApi, STATE } from '/services/youtube.js'
|
import { loadIframeApi, STATE } from '/services/youtube.js'
|
||||||
import { queue } from '/services/misc.js'
|
import { queue } from '/services/misc.js'
|
||||||
|
|
||||||
@ -9,48 +9,41 @@
|
|||||||
let player
|
let player
|
||||||
let animationFrameId
|
let animationFrameId
|
||||||
|
|
||||||
// output props
|
let currentTime
|
||||||
export let ready = false
|
let duration
|
||||||
export let ended = false
|
|
||||||
export let error = false
|
|
||||||
export let duration = null
|
|
||||||
export let currentTime = null
|
|
||||||
|
|
||||||
// input props
|
// input props
|
||||||
export let id
|
export let id
|
||||||
export let paused
|
export let paused
|
||||||
export let volume
|
export let volume
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
$: load(id)
|
$: load(id)
|
||||||
$: setPaused(paused)
|
$: paused ? pause() : play()
|
||||||
$: setVolume(volume)
|
$: setVolume(volume)
|
||||||
|
$: dispatch('timeupdate', currentTime)
|
||||||
|
$: dispatch('durationchange', duration)
|
||||||
|
|
||||||
const { enqueue, run } = queue()
|
const { enqueue, run } = queue()
|
||||||
|
|
||||||
export const load = (id) => enqueue((player) => {
|
export const load = (id) => enqueue((player) => {
|
||||||
ready = false
|
|
||||||
ended = false
|
|
||||||
error = false
|
|
||||||
currentTime = null
|
currentTime = null
|
||||||
duration = null
|
duration = null
|
||||||
|
|
||||||
if (paused) {
|
player.cueVideoById(id)
|
||||||
player.cueVideoById(id)
|
|
||||||
} else {
|
if (!paused) {
|
||||||
player.loadVideoById(id)
|
player.playVideo()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const setPaused = paused => enqueue(player => {
|
export const play = () => enqueue((player) => {
|
||||||
if (paused) {
|
player.playVideo()
|
||||||
if (player.getPlayerState() === STATE.PLAYING) {
|
})
|
||||||
player.pauseVideo()
|
|
||||||
}
|
export const pause = () => enqueue((player) => {
|
||||||
} else {
|
player.pauseVideo()
|
||||||
if (player.getPlayerState() !== STATE.PLAYING) {
|
|
||||||
player.playVideo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const setVolume = volume => enqueue(player => {
|
const setVolume = volume => enqueue(player => {
|
||||||
@ -61,68 +54,82 @@
|
|||||||
player.seekTo(seconds, allowSeekAhead)
|
player.seekTo(seconds, allowSeekAhead)
|
||||||
})
|
})
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
loadIframeApi().then(api => {
|
const api = await loadIframeApi()
|
||||||
element.id = Math.random().toString(16).slice(2, 8)
|
|
||||||
|
|
||||||
const onReady = ({ target: player }) => {
|
element.id = Math.random().toString(16).slice(2, 8)
|
||||||
if (player.isMuted()) {
|
|
||||||
player.unMute()
|
|
||||||
}
|
|
||||||
|
|
||||||
run(player)
|
const onReady = ({ target: player }) => {
|
||||||
|
if (player.isMuted()) {
|
||||||
|
player.unMute()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onStateChange = ({ data: state, target: player }) => {
|
run(player)
|
||||||
switch (state) {
|
}
|
||||||
case STATE.UNSTARTED:
|
|
||||||
ready = true
|
|
||||||
break
|
|
||||||
|
|
||||||
case STATE.PLAYING:
|
const onStateChange = ({ data: state, target: player }) => {
|
||||||
if (duration === null) {
|
switch (state) {
|
||||||
duration = player.getDuration()
|
case STATE.UNSTARTED:
|
||||||
}
|
break
|
||||||
|
|
||||||
break
|
case STATE.ENDED:
|
||||||
|
dispatch('ended')
|
||||||
|
break
|
||||||
|
|
||||||
case STATE.ENDED:
|
case STATE.PLAYING:
|
||||||
ended = true
|
dispatch('play')
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state === STATE.PLAYING) {
|
const newDuration = player.getDuration()
|
||||||
const step = () => {
|
|
||||||
currentTime = player.getCurrentTime()
|
if (duration !== newDuration) {
|
||||||
animationFrameId = requestAnimationFrame(step)
|
duration = newDuration
|
||||||
|
dispatch('durationchange', duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case STATE.PAUSED:
|
||||||
|
dispatch('pause')
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case STATE.CUED:
|
||||||
|
dispatch('canplay')
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === STATE.PLAYING) {
|
||||||
|
const step = () => {
|
||||||
|
currentTime = player.getCurrentTime()
|
||||||
animationFrameId = requestAnimationFrame(step)
|
animationFrameId = requestAnimationFrame(step)
|
||||||
} else {
|
}
|
||||||
if (animationFrameId) {
|
|
||||||
cancelAnimationFrame(animationFrameId)
|
step()
|
||||||
}
|
} else {
|
||||||
|
if (animationFrameId) {
|
||||||
|
cancelAnimationFrame(animationFrameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onError = () => {
|
const onError = error => {
|
||||||
error = true
|
dispatch('error', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
player = new api.Player(element.id, {
|
||||||
|
playerVars: {
|
||||||
|
autoplay: 0,
|
||||||
|
controls: 0,
|
||||||
|
enablejsapi: 1,
|
||||||
|
modestbranding: 1,
|
||||||
|
rel: 0
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
onReady,
|
||||||
|
onStateChange,
|
||||||
|
onError
|
||||||
}
|
}
|
||||||
|
|
||||||
player = new api.Player(element.id, {
|
|
||||||
playerVars: {
|
|
||||||
autoplay: 0,
|
|
||||||
controls: 0,
|
|
||||||
enablejsapi: 1,
|
|
||||||
modestbranding: 1,
|
|
||||||
rel: 0
|
|
||||||
},
|
|
||||||
events: {
|
|
||||||
onReady,
|
|
||||||
onStateChange,
|
|
||||||
onError
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
value={value}
|
value={value}
|
||||||
on:input
|
on:input
|
||||||
on:change
|
on:change
|
||||||
disabled={currentTime === null || duration === null}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="playerProgress__timecode">
|
<div class="playerProgress__timecode">
|
||||||
@ -21,13 +21,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import { secondsToElapsedTime } from '/services/misc.js'
|
import { secondsToElapsedTime } from '/services/misc.js'
|
||||||
|
|
||||||
export let duration
|
|
||||||
export let currentTime
|
|
||||||
export let ready
|
export let ready
|
||||||
|
export let currentTime
|
||||||
|
export let duration
|
||||||
|
|
||||||
$: value = currentTime != null ? currentTime : 0
|
$: value = currentTime != null ? currentTime : 0
|
||||||
$: max = duration != null ? duration : 100
|
$: max = duration != null ? duration : 0
|
||||||
$: currentPercent = currentTime != null ? (currentTime / duration) * 100 : 0
|
$: disabled = currentTime == null || duration == null
|
||||||
|
|
||||||
$: currentTimeText = currentTime != null ? secondsToElapsedTime(currentTime) : '--:--'
|
$: currentTimeText = currentTime != null ? secondsToElapsedTime(currentTime) : '--:--'
|
||||||
$: durationText = duration != null ? secondsToElapsedTime(duration) : '--:--'
|
$: durationText = duration != null ? secondsToElapsedTime(duration) : '--:--'
|
||||||
|
|
||||||
|
$: currentPercent = currentTime != null ? (currentTime / duration) * 100 : 0
|
||||||
</script>
|
</script>
|
@ -25,6 +25,7 @@ export const queue = () => {
|
|||||||
|
|
||||||
const enqueue = f => {
|
const enqueue = f => {
|
||||||
promise = promise.then(tap(f))
|
promise = promise.then(tap(f))
|
||||||
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
return { enqueue, run: deferred.resolve }
|
return { enqueue, run: deferred.resolve }
|
||||||
@ -89,6 +90,7 @@ export async function* tracksIterator(refererGenerator, cache) {
|
|||||||
media: {
|
media: {
|
||||||
title: metadata.title,
|
title: metadata.title,
|
||||||
url: mediaUrl,
|
url: mediaUrl,
|
||||||
|
cover: `https://img.youtube.com/vi/${mediaCredentials.id}/mqdefault.jpg`,
|
||||||
credentials: mediaCredentials
|
credentials: mediaCredentials
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user