UNPKG

@vime-js/standard

Version:
295 lines (253 loc) 9.5 kB
import { writable, derived } from 'svelte/store'; import PlayerState from './PlayerState'; import MediaType from './MediaType'; import VideoQuality from './VideoQuality'; import { private_writable, map_store_to_component, can_autoplay, selectable_if, rangeable_if, IS_MOBILE, indexable, private_writable_if, is_function, rangeable, } from '@vime-js/utils'; // Player defaults used when the `src` changes or `resetStore` is called. const playerDefaults = () => ({ paused: true, playing: false, seeking: false, rebuilding: false, internalTime: 0, currentTime: 0, title: '', duration: 0, buffered: 0, mediaId: null, currentSrc: null, buffering: false, videoQuality: VideoQuality.UNKNOWN, videoQualities: [], playbackRate: 1, playbackRates: [1], playbackStarted: false, playbackEnded: false, playbackReady: false, isLive: false, nativePoster: null, isControlsActive: true, }); const resetStore = (store) => { const defaults = playerDefaults(); Object.keys(defaults) .forEach((prop) => store[prop] && store[prop].set(defaults[prop])); }; const fillStore = async (store) => { store.canAutoplay.set(await can_autoplay(false)); store.canMutedAutoplay.set(await can_autoplay(true)); }; export const buildStandardStore = (player) => { const store = {}; const defaults = playerDefaults(); store.playbackReady = private_writable(defaults.playbackReady); store.rebuilding = private_writable_if(defaults.rebuilding, store.playbackReady); store.canAutoplay = private_writable(false); store.canMutedAutoplay = private_writable(false); store.canInteract = derived( [store.playbackReady, store.rebuilding], ([$playbackReady, $rebuilding]) => $playbackReady && !$rebuilding, ); // -------------------------------------------------------------- // Native // -------------------------------------------------------------- store.useNativeView = writable(true); store.useNativeControls = writable(true); store.useNativeCaptions = writable(true); store.nativePoster = private_writable(defaults.nativePoster); // -------------------------------------------------------------- // Src // -------------------------------------------------------------- store.src = writable(null); store.mediaId = private_writable(defaults.mediaId); store.poster = writable(null); store.provider = private_writable(null); store.providers = writable([]); store.providerConfig = writable({}); store.providerVersion = writable('latest'); store.origin = private_writable(null); store.title = private_writable(defaults.title); store.currentSrc = private_writable(defaults.currentSrc); store.Provider = derived( [store.src, store.providers], ([$src, $providers]) => $providers.find((p) => p.canPlay($src)), ); store.canSetPoster = derived( store.provider, ($provider) => $provider && is_function($provider.setPoster), ); // -------------------------------------------------------------- // Metadata // -------------------------------------------------------------- store.mediaType = private_writable(MediaType.NONE); store.isAudio = derived(store.mediaType, ($mediaType) => $mediaType === MediaType.AUDIO); store.isVideo = derived(store.mediaType, ($mediaType) => $mediaType === MediaType.VIDEO); store.isLive = private_writable(false); store.playbackRates = private_writable(defaults.playbackRates); store.videoQualities = private_writable(defaults.videoQualities); store.duration = private_writable(defaults.duration); // Used by @vime-js/complete. // eslint-disable-next-line no-underscore-dangle store._posterPlugin = writable(false); store.isVideoView = derived( // eslint-disable-next-line no-underscore-dangle [store.poster, store.nativePoster, store.canSetPoster, store._posterPlugin, store.isVideo], ([ $poster, $nativePoster, $canSetPoster, $plugin, $isVideo, ]) => !!(($canSetPoster || $plugin) && ($poster || $nativePoster)) || $isVideo, ); store.isVideoReady = derived( [store.playbackReady, store.isVideoView], ([$playbackReady, $isVideoView]) => $playbackReady && $isVideoView, ); // -------------------------------------------------------------- // Playback // -------------------------------------------------------------- store.canSetPlaybackRate = derived( [store.provider, store.playbackRates], ([ $provider, $playbackRates, ]) => $provider && $playbackRates.length > 1 && is_function($provider.setPlaybackRate), ); store.canSetVideoQuality = derived( [store.provider, store.isVideo, store.videoQualities], ([$provider, $isVideo, $videoQualities]) => $provider && $isVideo && $videoQualities.length > 0 && is_function($provider.setVideoQuality), ); store.paused = writable(defaults.paused); store.playbackRate = selectable_if( defaults.playbackRate, store.playbackRates, store.canSetPlaybackRate, ); store.videoQuality = selectable_if( defaults.videoQuality, store.videoQualities, store.canSetVideoQuality, ); store.currentTime = rangeable(defaults.currentTime, 0, store.duration); store.internalTime = private_writable(defaults.internalTime); store.muted = writable(false); store.volume = rangeable_if(30, 0, 100, !IS_MOBILE); store.buffered = private_writable(defaults.buffered); store.isControlsEnabled = writable(true); store.isControlsActive = private_writable(defaults.isControlsActive); store.progress = derived( [store.currentTime, store.duration, store.buffered], ([$currentTime, $duration, $buffered]) => ({ played: { seconds: $currentTime, percent: ($currentTime / $duration) * 100, }, buffered: { seconds: $buffered, percent: ($buffered / $duration) * 100, }, }), ); // -------------------------------------------------------------- // State // -------------------------------------------------------------- store.playing = private_writable(defaults.playing); store.buffering = private_writable(defaults.buffering); store.playbackEnded = private_writable(defaults.playbackEnded); store.playbackStarted = private_writable(defaults.playbackStarted); store.seeking = private_writable(defaults.seeking); store.isPlayerActive = private_writable(false); store.state = derived( [ store.playbackStarted, store.playbackEnded, store.paused, store.buffering, store.playbackReady, ], ([$playbackStarted, $playbackEnded, $paused, $buffering, $playbackReady]) => { if ($playbackEnded) { return PlayerState.ENDED; } if ($buffering) { return PlayerState.BUFFERING; } if ($playbackStarted && $paused) { return PlayerState.PAUSED; } if ($playbackStarted) { return PlayerState.PLAYING; } if ($playbackReady) { return PlayerState.CUED; } return PlayerState.IDLE; }, ); // -------------------------------------------------------------- // Tracks // -------------------------------------------------------------- store.canSetTracks = derived( store.provider, ($provider) => $provider && is_function($provider.setTracks), ); // Don't block writing of `tracks` as it might be stored and used by a provider when possible. store.tracks = writable([]); store.canSetTrack = derived( [store.provider, store.tracks], ([$provider, $tracks]) => $provider && $tracks && $tracks.length > 0 && is_function($provider.setTrack), ); // Can't block current track with `canSetTrack` because it'll stop @vime-js/complete from updating // the value when a plugin is managing captions. store.currentTrackIndex = indexable(store.tracks); store.currentTrack = derived( [store.tracks, store.currentTrackIndex], ([$tracks, $index]) => (($index >= 0) ? $tracks[$index] : null), ); store.isCaptionsActive = derived( [store.playbackReady, store.isAudio, store.currentTrackIndex], ([$playbackReady, $isAudio, $currentTrackIndex]) => $playbackReady && !$isAudio && ($currentTrackIndex !== -1), ); // TODO: add cues support (cues, currentCueIndex, currentCue, activeCues). // -------------------------------------------------------------- // Picture in Picture // -------------------------------------------------------------- store.canSetPiP = derived( [store.isVideoReady, store.provider], ([$isVideoReady, $provider]) => $isVideoReady && $provider && $provider.supportsPiP() && is_function($provider.setPiP), ); store.isPiPActive = private_writable(false); // -------------------------------------------------------------- // Fullscreen // -------------------------------------------------------------- // Set in the Player. store.canSetFullscreen = private_writable(false); store.isFullscreenActive = private_writable(false); // -------------------------------------------------------------- // Options // -------------------------------------------------------------- store.autopause = writable(true); store.aspectRatio = writable('16:9'); store.playsinline = writable(true); store.autoplay = writable(false); store.loop = writable(false); fillStore(store); return { store, onPropsChange: map_store_to_component(player, store), resetStore: () => resetStore(store), }; };