Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Video overlay #825

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/renderer/js/component/app/view.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import Router from "component/router/index";
import Router from "component/router";
import Header from "component/header";
import Theme from "component/theme";
import VideoOverlay from "component/videoOverlay";
import ModalRouter from "modal/modalRouter";
import lbry from "lbry";
import throttle from "util/throttle";
Expand Down Expand Up @@ -57,6 +58,7 @@ class App extends React.PureComponent {
<Theme />
<Header />
<div id="main-content">
<VideoOverlay />
<Router />
</div>
<ModalRouter />
Expand Down
19 changes: 19 additions & 0 deletions src/renderer/js/component/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,22 @@ export class Thumbnail extends React.PureComponent {
);
}
}

export class LoadingScreen extends React.PureComponent {
static defaultProps = {
spinner: true,
};

render() {
const { status, spinner } = this.props;
return (
<div className="video__loading-screen">
<div>
{spinner && <div className="video__loading-spinner" />}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the <Spinner /> component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed one thing. We already have a common.js file here(file 1), but the <Spinner /> component comes from here(folder 1), a new common folder with just that component.
Are we breaking down file 1 to individual components and putting them in folder 1? Or should I include <Spinner /> component in file 1. The latter option is better IMO as then we don't have to include different files for each "common" component, unless former is better for some use cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hackrush01 @seanyesmunt @liamcardenas I think common.js should die and these should all just be individual components.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree


<div className="video__loading-status">{status}</div>
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import { doChangeVolume } from "redux/actions/app";
import { selectVolume } from "redux/selectors/app";
import { doPlayUri, doSetPlayingUri } from "redux/actions/content";
import {
makeSelectMetadataForUri,
Expand All @@ -14,8 +12,8 @@ import {
} from "redux/selectors/file_info";
import { makeSelectCostInfoForUri } from "redux/selectors/cost_info";
import { selectShowNsfw } from "redux/selectors/settings";
import Video from "./view";
import { selectPlayingUri } from "redux/selectors/content";
import Media from "./view";
import { selectPlayingUri, selectOverlayable } from "redux/selectors/content";

const select = (state, props) => ({
costInfo: makeSelectCostInfoForUri(props.uri)(state),
Expand All @@ -25,14 +23,13 @@ const select = (state, props) => ({
isLoading: makeSelectLoadingForUri(props.uri)(state),
isDownloading: makeSelectDownloadingForUri(props.uri)(state),
playingUri: selectPlayingUri(state),
overlayable: selectOverlayable(state),
contentType: makeSelectContentTypeForUri(props.uri)(state),
volume: selectVolume(state),
});

const perform = dispatch => ({
play: uri => dispatch(doPlayUri(uri)),
cancelPlay: () => dispatch(doSetPlayingUri(null)),
changeVolume: volume => dispatch(doChangeVolume(volume)),
});

export default connect(select, perform)(Video);
export default connect(select, perform)(Media);
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,16 @@ class VideoPlayButton extends React.PureComponent {
"Space" === event.code
) {
event.preventDefault();
this.watch();
this.renderMedia();
}
}

watch() {
renderMedia() {
this.props.play(this.props.uri);
}

render() {
const { button, label, isLoading, fileInfo, mediaType } = this.props;

/*
title={
isLoading ? "Video is Loading" :
!costInfo ? "Waiting on cost info..." :
fileInfo === undefined ? "Waiting on file info..." : ""
}
*/
const { isLoading, fileInfo, mediaType } = this.props;

const disabled = isLoading || fileInfo === undefined;
const icon =
Expand All @@ -44,12 +36,10 @@ class VideoPlayButton extends React.PureComponent {

return (
<Link
button={button ? button : null}
disabled={disabled}
label={label ? label : ""}
className="video__play-button"
icon={icon}
onClick={() => this.watch()}
onClick={() => this.renderMedia()}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,116 +1,119 @@
import React from "react";
import lbry from "lbry";
import VideoPlayer from "./internal/player";
import VideoPlayButton from "./internal/play-button";
import LoadingScreen from "./internal/loading-screen";
import { LoadingScreen } from "component/common";
import VideoPlayer from "component/videoPlayer";
import NsfwOverlay from "component/nsfwOverlay";

class Video extends React.PureComponent {
class Media extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
showNsfwHelp: false,
};
}

componentWillUnmount() {
this.props.cancelPlay();
componentWillMount() {
const { uri, playingUri } = this.props;

// If not on the same uri cancel playback
if (uri !== playingUri) {
this.props.cancelPlay();
}
}

isMediaSame(nextProps) {
return (
this.props.fileInfo &&
nextProps.fileInfo &&
this.props.fileInfo.outpoint === nextProps.fileInfo.outpoint
);
isNSFW() {
const { obscureNsfw, metadata } = this.props;
return obscureNsfw && metadata && metadata.nsfw;
}

handleMouseOver() {
if (
this.props.obscureNsfw &&
this.props.metadata &&
this.props.metadata.nsfw
) {
this.setState({
showNsfwHelp: true,
});
}
if (this.isNSFW()) this.setState({ showNsfwHelp: true });
}

handleMouseOut() {
if (this.state.showNsfwHelp) {
this.setState({
showNsfwHelp: false,
});
this.setState({ showNsfwHelp: false });
}

determineLoadStatusMessage() {
const { fileInfo, isLoading, isDownloading } = this.props;

let loadStatusMessage = "";

if (fileInfo && fileInfo.completed && !fileInfo.written_bytes) {
loadStatusMessage = __(
"It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds."
);
} else if (isLoading) {
loadStatusMessage = __("Requesting stream...");
} else if (isDownloading) {
loadStatusMessage = __("Downloading stream... not long left now!");
}

return loadStatusMessage;
}

determineClasses(isPlaying, mediaType) {
const { isLoading, isDownloading, overlay, overlayable } = this.props;

let classes = [];
classes.push(this.isNSFW() ? "video--obscured " : "");

if (isLoading || isDownloading) classes.push("media-embedded", "video");

if (mediaType === "video") {
classes.push("media-embedded", "video");
classes.push(isPlaying ? "video--active" : "video--hidden");
} else if (mediaType === "application") {
classes.push("media-embedded");
} else if (!isPlaying) {
classes.push("media-embedded");
}
if (overlay && overlayable) {
classes.push("overlay");

// We remove media-embedded on the overlay
if (classes.indexOf("media-embedded") != -1) {
classes.splice(classes.indexOf("media-embedded"), 1);
}
}

return classes.join(" ").trim();
}

render() {
const {
metadata,
isLoading,
isDownloading,
playingUri,
fileInfo,
contentType,
changeVolume,
volume,
uri,
overlay,
overlayable,
} = this.props;

const isPlaying = playingUri === uri;
const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const mediaType = lbry.getMediaType(
contentType,
fileInfo && fileInfo.file_name
);

let loadStatusMessage = "";

if (fileInfo && fileInfo.completed && !fileInfo.written_bytes) {
loadStatusMessage = __(
"It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds."
);
} else if (isLoading) {
loadStatusMessage = __("Requesting stream...");
} else if (isDownloading) {
loadStatusMessage = __("Downloading stream... not long left now!");
}

let klasses = [];
klasses.push(obscureNsfw ? "video--obscured " : "");
if (isLoading || isDownloading) klasses.push("video-embedded", "video");
if (mediaType === "video") {
klasses.push("video-embedded", "video");
klasses.push(isPlaying ? "video--active" : "video--hidden");
} else if (mediaType === "application") {
klasses.push("video-embedded");
} else {
if (!isPlaying) klasses.push("video-embedded");
if (overlay && !overlayable) {
return null;
}
const poster = metadata.thumbnail;

return (
<div
className={klasses.join(" ")}
className={this.determineClasses(isPlaying, mediaType)}
onMouseEnter={this.handleMouseOver.bind(this)}
onMouseLeave={this.handleMouseOut.bind(this)}
>
{isPlaying &&
(!isReadyToPlay ? (
<LoadingScreen status={loadStatusMessage} />
<LoadingScreen status={this.determineLoadStatusMessage()} />
) : (
<VideoPlayer
filename={fileInfo.file_name}
poster={poster}
downloadPath={fileInfo.download_path}
mediaType={mediaType}
contentType={contentType}
downloadCompleted={fileInfo.completed}
changeVolume={changeVolume}
volume={volume}
/>
<VideoPlayer overlay={overlay} uri={uri} />
))}
{!isPlaying && (
<div
Expand All @@ -126,4 +129,4 @@ class Video extends React.PureComponent {
}
}

export default Video;
export default Media;
14 changes: 0 additions & 14 deletions src/renderer/js/component/video/internal/loading-screen.jsx

This file was deleted.

19 changes: 19 additions & 0 deletions src/renderer/js/component/videoOverlay/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { connect } from "react-redux";
import {
makeSelectFileInfoForUri,
makeSelectDownloadingForUri,
makeSelectLoadingForUri,
} from "redux/selectors/file_info";
import { selectCurrentPage } from "redux/selectors/navigation";
import { selectPlayingUri } from "redux/selectors/content";
import VideoOverlay from "./view";

const select = (state, props) => ({
playingUri: selectPlayingUri(state),
currentPage: selectCurrentPage(state),
isDownloading: uri => makeSelectDownloadingForUri(uri)(state),
isLoading: uri => makeSelectLoadingForUri(uri)(state),
fileInfo: uri => makeSelectFileInfoForUri(uri)(state),
});

export default connect(select, null)(VideoOverlay);
23 changes: 23 additions & 0 deletions src/renderer/js/component/videoOverlay/view.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import Media from "component/media";

class VideoOverlay extends React.PureComponent {
render() {
const { playingUri, currentPage } = this.props;

const isDownloading = this.props.isDownloading(playingUri);
const isLoading = this.props.isLoading(playingUri);
const fileInfo = this.props.fileInfo(playingUri);
const haveFileInfo = fileInfo && fileInfo.written_bytes > 0;

const isReadyToPlay = (haveFileInfo || isDownloading) && !isLoading;

if (isReadyToPlay && playingUri !== null && currentPage !== "show") {
return <Media overlay={true} uri={playingUri} />;
}

return null;
}
}

export default VideoOverlay;
Loading