react-player
Version:
A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
259 lines (258 loc) • 8.19 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import React, { Component } from "react";
import isEqual from "react-fast-compare";
import { propTypes, defaultProps } from "./props.js";
import { isMediaStream } from "./utils.js";
const SEEK_ON_PLAY_EXPIRY = 5e3;
class Player extends Component {
constructor() {
super(...arguments);
__publicField(this, "mounted", false);
__publicField(this, "isReady", false);
__publicField(this, "isPlaying", false);
// Track playing state internally to prevent bugs
__publicField(this, "isLoading", true);
// Use isLoading to prevent onPause when switching URL
__publicField(this, "loadOnReady", null);
__publicField(this, "startOnPlay", true);
__publicField(this, "seekOnPlay", null);
__publicField(this, "onDurationCalled", false);
__publicField(this, "handlePlayerMount", (player) => {
if (this.player) {
this.progress();
return;
}
this.player = player;
this.player.load(this.props.url);
this.progress();
});
__publicField(this, "getInternalPlayer", (key) => {
if (!this.player)
return null;
return this.player[key];
});
__publicField(this, "progress", () => {
if (this.props.url && this.player && this.isReady) {
const playedSeconds = this.getCurrentTime() || 0;
const loadedSeconds = this.getSecondsLoaded();
const duration = this.getDuration();
if (duration) {
const progress = {
playedSeconds,
played: playedSeconds / duration
};
if (loadedSeconds !== null) {
progress.loadedSeconds = loadedSeconds;
progress.loaded = loadedSeconds / duration;
}
if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {
this.props.onProgress(progress);
}
this.prevPlayed = progress.playedSeconds;
this.prevLoaded = progress.loadedSeconds;
}
}
this.progressTimeout = setTimeout(this.progress, this.props.progressFrequency || this.props.progressInterval);
});
__publicField(this, "handleReady", () => {
if (!this.mounted)
return;
this.isReady = true;
this.isLoading = false;
const { onReady, playing, volume, muted } = this.props;
onReady();
if (!muted && volume !== null) {
this.player.setVolume(volume);
}
if (this.loadOnReady) {
this.player.load(this.loadOnReady, true);
this.loadOnReady = null;
} else if (playing) {
this.player.play();
}
this.handleDurationCheck();
});
__publicField(this, "handlePlay", () => {
this.isPlaying = true;
this.isLoading = false;
const { onStart, onPlay, playbackRate } = this.props;
if (this.startOnPlay) {
if (this.player.setPlaybackRate && playbackRate !== 1) {
this.player.setPlaybackRate(playbackRate);
}
onStart();
this.startOnPlay = false;
}
onPlay();
if (this.seekOnPlay) {
this.seekTo(this.seekOnPlay);
this.seekOnPlay = null;
}
this.handleDurationCheck();
});
__publicField(this, "handlePause", (e) => {
this.isPlaying = false;
if (!this.isLoading) {
this.props.onPause(e);
}
});
__publicField(this, "handleEnded", () => {
const { activePlayer, loop, onEnded } = this.props;
if (activePlayer.loopOnEnded && loop) {
this.seekTo(0);
}
if (!loop) {
this.isPlaying = false;
onEnded();
}
});
__publicField(this, "handleError", (...args) => {
this.isLoading = false;
this.props.onError(...args);
});
__publicField(this, "handleDurationCheck", () => {
clearTimeout(this.durationCheckTimeout);
const duration = this.getDuration();
if (duration) {
if (!this.onDurationCalled) {
this.props.onDuration(duration);
this.onDurationCalled = true;
}
} else {
this.durationCheckTimeout = setTimeout(this.handleDurationCheck, 100);
}
});
__publicField(this, "handleLoaded", () => {
this.isLoading = false;
});
}
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
clearTimeout(this.progressTimeout);
clearTimeout(this.durationCheckTimeout);
if (this.isReady && this.props.stopOnUnmount) {
this.player.stop();
if (this.player.disablePIP) {
this.player.disablePIP();
}
}
this.mounted = false;
}
componentDidUpdate(prevProps) {
if (!this.player) {
return;
}
const { url, playing, volume, muted, playbackRate, pip, loop, activePlayer, disableDeferredLoading } = this.props;
if (!isEqual(prevProps.url, url)) {
if (this.isLoading && !activePlayer.forceLoad && !disableDeferredLoading && !isMediaStream(url)) {
console.warn(`ReactPlayer: the attempt to load ${url} is being deferred until the player has loaded`);
this.loadOnReady = url;
return;
}
this.isLoading = true;
this.startOnPlay = true;
this.onDurationCalled = false;
this.player.load(url, this.isReady);
}
if (!prevProps.playing && playing && !this.isPlaying) {
this.player.play();
}
if (prevProps.playing && !playing && this.isPlaying) {
this.player.pause();
}
if (!prevProps.pip && pip && this.player.enablePIP) {
this.player.enablePIP();
}
if (prevProps.pip && !pip && this.player.disablePIP) {
this.player.disablePIP();
}
if (prevProps.volume !== volume && volume !== null) {
this.player.setVolume(volume);
}
if (prevProps.muted !== muted) {
if (muted) {
this.player.mute();
} else {
this.player.unmute();
if (volume !== null) {
setTimeout(() => this.player.setVolume(volume));
}
}
}
if (prevProps.playbackRate !== playbackRate && this.player.setPlaybackRate) {
this.player.setPlaybackRate(playbackRate);
}
if (prevProps.loop !== loop && this.player.setLoop) {
this.player.setLoop(loop);
}
}
getDuration() {
if (!this.isReady)
return null;
return this.player.getDuration();
}
getCurrentTime() {
if (!this.isReady)
return null;
return this.player.getCurrentTime();
}
getSecondsLoaded() {
if (!this.isReady)
return null;
return this.player.getSecondsLoaded();
}
seekTo(amount, type, keepPlaying) {
if (!this.isReady) {
if (amount !== 0) {
this.seekOnPlay = amount;
setTimeout(() => {
this.seekOnPlay = null;
}, SEEK_ON_PLAY_EXPIRY);
}
return;
}
const isFraction = !type ? amount > 0 && amount < 1 : type === "fraction";
if (isFraction) {
const duration = this.player.getDuration();
if (!duration) {
console.warn("ReactPlayer: could not seek using fraction \u2013\xA0duration not yet available");
return;
}
this.player.seekTo(duration * amount, keepPlaying);
return;
}
this.player.seekTo(amount, keepPlaying);
}
render() {
const Player2 = this.props.activePlayer;
if (!Player2) {
return null;
}
return /* @__PURE__ */ React.createElement(
Player2,
{
...this.props,
onMount: this.handlePlayerMount,
onReady: this.handleReady,
onPlay: this.handlePlay,
onPause: this.handlePause,
onEnded: this.handleEnded,
onLoaded: this.handleLoaded,
onError: this.handleError
}
);
}
}
__publicField(Player, "displayName", "Player");
__publicField(Player, "propTypes", propTypes);
__publicField(Player, "defaultProps", defaultProps);
export {
Player as default
};