UNPKG

@ktt45678/vidstack

Version:

UI component library for building high-quality, accessible video and audio experiences on the web.

320 lines (317 loc) 8.78 kB
import '../chunks/vidstack-DgZku5BZ.js'; import '../chunks/vidstack-Dpmcetl_.js'; import '../chunks/vidstack-CdS1WNqk.js'; import { createDisposalBin, isString, setStyle, isBoolean, DOMEvent } from '../chunks/vidstack-41uXLVgN.js'; import { mediaState, canPlayVideoType } from '../chunks/vidstack-Dv-j8Hw0.js'; import '@floating-ui/dom'; import '../chunks/vidstack-DPeH8lGJ.js'; import '../chunks/vidstack-DKuBmwBi.js'; import '../chunks/vidstack-BOTZD4tC.js'; import '../chunks/vidstack-BI9udY6A.js'; import 'media-captions'; import 'lit-html'; import '../chunks/vidstack-BuhgbZ2O.js'; import '../chunks/vidstack-Bw60Npp4.js'; import 'lit-html/directives/if-defined.js'; import 'lit-html/directives/unsafe-svg.js'; import 'lit-html/async-directive.js'; import '../chunks/vidstack-D2YigfqZ.js'; import 'lit-html/directives/unsafe-html.js'; let activePlyr = null, defaults = mediaState.record, eventMap = { ratechange: "rate-change", ready: "can-play", timeupdate: "time-update", volumechange: "volume-change" }; class Plyr { constructor(target, config = {}) { this.target = target; this.config = config; this.fullscreen = new PlyrFullscreenAdapter(this); // These are only included for type defs, props are defined in constructor. this.playing = defaults.playing; this.paused = defaults.paused; this.ended = defaults.ended; this.currentTime = defaults.currentTime; this.seeking = defaults.seeking; this.duration = defaults.duration; this.volume = defaults.volume; this.muted = defaults.muted; this.loop = defaults.loop; this.poster = defaults.poster; this._source = null; this._ratio = null; this._disposal = createDisposalBin(); this._listeners = []; { throw Error("[plyr] can not create player on server."); } } static setup(targets, config) { if (isString(targets)) { targets = document.querySelectorAll(targets); } return [...targets].map((target) => new Plyr(target, config)); } static supported(type, provider) { return true; } get type() { return this.player.provider?.type ?? ""; } get isHTML5() { return /audio|video|hls/.test(this.type); } get isEmbed() { return /youtube|vimeo/.test(this.type); } get buffered() { const { bufferedEnd, seekableEnd } = this.player.state; return seekableEnd > 0 ? bufferedEnd / seekableEnd : 0; } get stopped() { return this.paused && this.currentTime === 0; } get hasAudio() { if (!this.isHTML5) return true; const media = this.player.provider.media; return Boolean( media.mozHasAudio || media.webkitAudioDecodedByteCount || media.audioTracks?.length || this.player.audioTracks.length ); } get speed() { return this.player.playbackRate; } set speed(speed) { this.player.remoteControl.changePlaybackRate(speed); } get currentTrack() { return this.player.textTracks.selectedIndex; } set currentTrack(index) { this.player.remoteControl.changeTextTrackMode(index, "showing"); } get pip() { return this.player.state.pictureInPicture; } set pip(isActive) { if (isActive) this.player.enterPictureInPicture(); else this.player.exitPictureInPicture(); } get quality() { return this.player.state.quality?.height ?? null; } set quality(value) { let qualities = this.player.qualities, index = -1; if (value !== null) { let minScore = Infinity; for (let i = 0; i < qualities.length; i++) { const score = Math.abs(qualities[i].height - value); if (score < minScore) { index = i; minScore = score; } } } this.player.remoteControl.changeQuality(index); } get source() { return this._source; } set source(source) { const { type: viewType = "video", sources = "", title = "", poster = "", thumbnails = "", tracks = [] } = source ?? {}; this.player.src = sources; this.player.viewType = viewType; this.player.title = title; this.player.poster = poster; this.layout.thumbnails = thumbnails; this.player.textTracks.clear(); for (const track of tracks) this.player.textTracks.add(track); this._source = source; } get ratio() { return this._ratio; } set ratio(ratio) { if (ratio) ratio = ratio.replace(/\s*:\s*/, " / "); setStyle(this.player, "aspect-ratio", ratio ?? "unset"); this._ratio = ratio; } get download() { return this.layout.download; } set download(download) { this.layout.download = download; } _onPlay() { if (activePlyr !== this) activePlyr?.pause(); activePlyr = this; } _onReset() { this.currentTime = 0; this.paused = true; } play() { return this.player.play(); } pause() { return this.player.pause(); } togglePlay(toggle = this.paused) { if (toggle) { return this.player.play(); } else { return this.player.pause(); } } toggleCaptions(toggle = !this.player.textTracks.selected) { const controller = this.player.remoteControl; if (toggle) { controller.showCaptions(); } else { controller.disableCaptions(); } } toggleControls(toggle = !this.player.controls.showing) { const controls = this.player.controls; if (toggle) { controls.show(); } else { controls.hide(); } } restart() { this.currentTime = 0; } stop() { this.pause(); this.player.currentTime = 0; } forward(seekTime = this.config.seekTime ?? 10) { this.currentTime += seekTime; } rewind(seekTime = this.config.seekTime ?? 10) { this.currentTime -= seekTime; } increaseVolume(step = 5) { this.volume += step; } decreaseVolume(step = 5) { this.volume -= step; } airplay() { return this.player.requestAirPlay(); } on(type, callback) { this._listen(type, callback); } once(type, callback) { this._listen(type, callback, { once: true }); } off(type, callback) { this._listen(type, callback, { remove: true }); } _listen(type, callback, options = {}) { let eventType = type, toggle = null; switch (type) { case "captionsenabled": case "captionsdisabled": eventType = "text-track-change"; toggle = type === "captionsenabled"; break; case "controlsshown": case "controlshidden": eventType = "controls-change"; toggle = type === "controlsshown"; break; case "enterfullscreen": case "exitfullscreen": eventType = "fullscreen-change"; toggle = type === "enterfullscreen"; break; } const mappedEventType = eventMap[eventType] ?? eventType; const listener = (event) => { if (isBoolean(toggle) && !!event.detail !== toggle) return; if (mappedEventType !== type) { callback(new DOMEvent(type, { ...event, trigger: event })); return; } callback(event); }; if (options.remove) { let index = -1; do { index = this._listeners.findIndex((t) => t.type === type && t.callback === callback); if (index >= 0) { const { listener: listener2 } = this._listeners[index]; this.player.removeEventListener(mappedEventType, listener2); this._listeners.splice(index, 1); } } while (index >= 0); } else { this._listeners.push({ type, callback, listener }); this.player.addEventListener(mappedEventType, listener, { once: options.once }); } } supports(type) { return !!type && canPlayVideoType(); } destroy() { for (const { type, listener } of this._listeners) { this.player.removeEventListener(eventMap[type] ?? type, listener); } this._source = null; this._listeners.length = 0; if (activePlyr === this) activePlyr = null; this._disposal.empty(); this.player.destroy(); } } class PlyrFullscreenAdapter { constructor(_plyr) { this._plyr = _plyr; } get _player() { return this._plyr.player; } /** * Returns a boolean indicating if the current player has fullscreen enabled. */ get enabled() { return this._player.state.canFullscreen; } /** * Returns a boolean indicating if the current player is in fullscreen mode. */ get active() { return this._player.state.fullscreen; } /** * Request to enter fullscreen. */ enter() { return this._player.requestFullscreen(); } /** * Request to exit fullscreen. */ exit() { return this._player.exitFullscreen(); } /** * Request to toggle fullscreen. */ toggle() { if (this.active) return this.exit(); else return this.enter(); } } export { Plyr, PlyrFullscreenAdapter };