lbry-desktop/ui/js/component/video/internal/player.jsx

182 lines
5 KiB
React
Raw Normal View History

const { remote } = require("electron");
import React from "react";
import { Thumbnail } from "component/common";
import player from "render-media";
import fs from "fs";
2017-07-02 17:35:30 +02:00
import { setSession, getSession } from "utils";
import LoadingScreen from "./loading-screen";
2017-06-09 01:41:44 +02:00
class VideoPlayer extends React.PureComponent {
2017-07-06 19:33:44 +02:00
static MP3_CONTENT_TYPES = ["audio/mpeg3", "audio/mpeg"];
constructor(props) {
super(props);
this.state = {
hasMetadata: false,
startedPlaying: false,
unplayable: false,
};
2017-07-01 23:57:14 +02:00
this.togglePlayListener = this.togglePlay.bind(this);
}
componentDidMount() {
2017-07-02 12:09:26 +02:00
const component = this;
const container = this.refs.media;
2017-07-06 19:33:44 +02:00
const { contentType, downloadPath, mediaType } = this.props;
const loadedMetadata = e => {
2017-07-06 19:33:44 +02:00
this.setState({ hasMetadata: true, startedPlaying: true });
this.refs.media.children[0].play();
};
const renderMediaCallback = err => {
if (err) this.setState({ unplayable: true });
};
// Handle fullscreen change for the Windows platform
const win32FullScreenChange = e => {
const win = remote.BrowserWindow.getFocusedWindow();
if ("win32" === process.platform) {
win.setMenu(
document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu()
);
}
};
2017-07-06 19:33:44 +02:00
// use renderAudio override for mp3
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
this.renderAudio(container, false);
} else {
player.append(
this.file(),
container,
{ autoplay: false, controls: true },
renderMediaCallback.bind(this)
);
}
2017-07-01 23:57:14 +02:00
document.addEventListener("keydown", this.togglePlayListener);
const mediaElement = this.refs.media.children[0];
if (mediaElement) {
mediaElement.addEventListener("click", this.togglePlayListener);
mediaElement.addEventListener(
"loadedmetadata",
loadedMetadata.bind(this),
{
once: true,
}
);
mediaElement.addEventListener(
"webkitfullscreenchange",
win32FullScreenChange.bind(this)
);
2017-07-01 23:38:09 +02:00
mediaElement.addEventListener("volumechange", () => {
2017-07-02 17:35:30 +02:00
setSession("prefs_volume", mediaElement.volume);
2017-07-01 23:38:09 +02:00
});
mediaElement.volume = this.getPreferredVolume();
2017-07-01 23:57:14 +02:00
}
}
componentWillUnmount() {
document.removeEventListener("keydown", this.togglePlayListener);
const mediaElement = this.refs.media.children[0];
if (mediaElement) {
mediaElement.removeEventListener("click", this.togglePlayListener);
}
}
2017-07-06 19:33:44 +02:00
renderAudio(container, autoplay) {
const { downloadPath } = this.props;
const audio = document.createElement("audio");
audio.autoplay = autoplay;
audio.controls = true;
audio.src = downloadPath;
container.appendChild(audio);
}
2017-07-01 22:33:23 +02:00
togglePlay(event) {
// ignore all events except click and spacebar keydown, or input events in a form control
if (
"keydown" === event.type &&
("Space" !== event.code || "input" === event.target.tagName.toLowerCase())
) {
2017-07-01 22:33:23 +02:00
return;
}
event.preventDefault();
const mediaElement = this.refs.media.children[0];
if (mediaElement) {
if (!mediaElement.paused) {
mediaElement.pause();
} else {
mediaElement.play();
}
}
}
2017-07-01 23:38:09 +02:00
getPreferredVolume() {
2017-07-02 17:35:30 +02:00
const volumePreference = parseFloat(getSession("prefs_volume"));
2017-07-01 23:38:09 +02:00
return isNaN(volumePreference) ? 1 : volumePreference;
}
componentDidUpdate() {
2017-07-06 19:33:44 +02:00
const { contentType, downloadCompleted } = this.props;
const { startedPlaying } = this.state;
if (this.playableType() && !startedPlaying && downloadCompleted) {
const container = this.refs.media.children[0];
2017-07-06 19:33:44 +02:00
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
this.renderAudio(container, true);
} else {
player.render(this.file(), container, {
autoplay: true,
controls: true,
});
}
}
}
file() {
const { downloadPath, filename } = this.props;
2017-07-06 19:44:52 +02:00
return {
name: filename,
createReadStream: opts => {
return fs.createReadStream(downloadPath, opts);
},
};
}
2017-07-06 19:44:52 +02:00
playableType() {
const { mediaType } = this.props;
return ["audio", "video"].indexOf(mediaType) !== -1;
}
render() {
const { mediaType, poster } = this.props;
const { hasMetadata, unplayable } = this.state;
const noMetadataMessage = "Waiting for metadata.";
const unplayableMessage = "Sorry, looks like we can't play this file.";
const needsMetadata = this.playableType();
return (
<div>
{["audio", "application"].indexOf(mediaType) !== -1 &&
(!this.playableType() || hasMetadata) &&
!unplayable &&
<Thumbnail src={poster} className="video-embedded" />}
{this.playableType() &&
!hasMetadata &&
!unplayable &&
<LoadingScreen status={noMetadataMessage} />}
{unplayable &&
<LoadingScreen status={unplayableMessage} spinner={false} />}
<div ref="media" />
</div>
);
}
}
export default VideoPlayer;