"Fixed NSFW content showing on filePage"

NSFW content is obscured on show page and gives an overlay to inform
the user. Fixes #286

Added one additional format(epub) in lbry.js.
This commit is contained in:
hackrush 2017-06-26 19:30:24 +05:30 committed by Jeremy Kauffman
parent 6aad233f66
commit e3bbb6fcef
12 changed files with 89 additions and 45 deletions

View file

@ -1,10 +1,10 @@
import React from "react"; import React from "react";
import lbry from "lbry.js";
import lbryuri from "lbryuri.js"; import lbryuri from "lbryuri.js";
import Link from "component/link"; import Link from "component/link";
import { Thumbnail, TruncatedText, Icon } from "component/common"; import { TruncatedText, Icon } from "component/common";
import FilePrice from "component/filePrice"; import FilePrice from "component/filePrice";
import UriIndicator from "component/uriIndicator"; import UriIndicator from "component/uriIndicator";
import NsfwOverlay from "component/nsfwOverlay";
class FileCard extends React.PureComponent { class FileCard extends React.PureComponent {
constructor(props) { constructor(props) {
@ -97,22 +97,8 @@ class FileCard extends React.PureComponent {
<TruncatedText lines={2}>{description}</TruncatedText> <TruncatedText lines={2}>{description}</TruncatedText>
</div> </div>
</Link> </Link>
{obscureNsfw &&
this.state.hovered &&
<div className="card-overlay">
<p>
{__(
"This content is Not Safe For Work. To view adult content, please change your"
)}
{" "}
<Link
className="button-text"
onClick={() => navigate("settings")}
label={__("Settings")}
/>.
</p>
</div>}
</div> </div>
{obscureNsfw && this.state.hovered && <NsfwOverlay />}
</section> </section>
); );
} }

View file

@ -2,10 +2,9 @@ import React from "react";
import lbry from "lbry.js"; import lbry from "lbry.js";
import lbryuri from "lbryuri.js"; import lbryuri from "lbryuri.js";
import Link from "component/link"; import Link from "component/link";
import FileActions from "component/fileActions"; import { TruncatedText } from "component/common.js";
import { Thumbnail, TruncatedText } from "component/common.js";
import FilePrice from "component/filePrice"; import FilePrice from "component/filePrice";
import UriIndicator from "component/uriIndicator"; import NsfwOverlay from "component/nsfwOverlay";
class FileTile extends React.PureComponent { class FileTile extends React.PureComponent {
static SHOW_EMPTY_PUBLISH = "publish"; static SHOW_EMPTY_PUBLISH = "publish";
@ -124,20 +123,7 @@ class FileTile extends React.PureComponent {
</div> </div>
</div> </div>
</Link> </Link>
{this.state.showNsfwHelp && {this.state.showNsfwHelp && <NsfwOverlay />}
<div className="card-overlay">
<p>
{__(
"This content is Not Safe For Work. To view adult content, please change your"
)}
{" "}
<Link
className="button-text"
onClick={() => navigate("/settings")}
label={__("Settings")}
/>.
</p>
</div>}
</section> </section>
); );
} }

View file

@ -0,0 +1,10 @@
import React from "react";
import { connect } from "react-redux";
import { doNavigate } from "actions/app";
import NsfwOverlay from "./view";
const perform = dispatch => ({
navigateSettings: () => dispatch(doNavigate("/settings")),
});
export default connect(null, perform)(NsfwOverlay);

View file

@ -0,0 +1,22 @@
import React from "react";
import Link from "component/link";
const NsfwOverlay = props => {
return (
<div className="card-overlay">
<p>
{__(
"This content is Not Safe For Work. To view adult content, please change your"
)}{" "}
{" "}{" "}
<Link
className="button-text"
onClick={() => props.navigateSettings()}
label={__("Settings")}
/>.
</p>
</div>
);
};
export default NsfwOverlay;

View file

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doCloseModal } from "actions/app"; import { doCloseModal } from "actions/app";
import { doNavigate } from "actions/app";
import { selectCurrentModal } from "selectors/app"; import { selectCurrentModal } from "selectors/app";
import { doPurchaseUri, doLoadVideo } from "actions/content"; import { doPurchaseUri, doLoadVideo } from "actions/content";
import { import {
@ -13,6 +14,7 @@ import {
makeSelectDownloadingForUri, makeSelectDownloadingForUri,
} from "selectors/file_info"; } from "selectors/file_info";
import { makeSelectCostInfoForUri } from "selectors/cost_info"; import { makeSelectCostInfoForUri } from "selectors/cost_info";
import { selectObscureNsfw } from "selectors/app";
import Video from "./view"; import Video from "./view";
const makeSelect = () => { const makeSelect = () => {
@ -27,6 +29,7 @@ const makeSelect = () => {
costInfo: selectCostInfo(state, props), costInfo: selectCostInfo(state, props),
fileInfo: selectFileInfo(state, props), fileInfo: selectFileInfo(state, props),
metadata: selectMetadata(state, props), metadata: selectMetadata(state, props),
obscureNsfw: selectObscureNsfw(state),
modal: selectCurrentModal(state), modal: selectCurrentModal(state),
isLoading: selectIsLoading(state, props), isLoading: selectIsLoading(state, props),
isDownloading: selectIsDownloading(state, props), isDownloading: selectIsDownloading(state, props),

View file

@ -3,11 +3,15 @@ import lbry from "lbry";
import VideoPlayer from "./internal/player"; import VideoPlayer from "./internal/player";
import VideoPlayButton from "./internal/play-button"; import VideoPlayButton from "./internal/play-button";
import LoadingScreen from "./internal/loading-screen"; import LoadingScreen from "./internal/loading-screen";
import NsfwOverlay from "component/nsfwOverlay";
class Video extends React.PureComponent { class Video extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { isPlaying: false }; this.state = {
isPlaying: false,
showNsfwHelp: false,
};
} }
startPlaying() { startPlaying() {
@ -16,6 +20,26 @@ class Video extends React.PureComponent {
}); });
} }
handleMouseOver() {
if (
this.props.obscureNsfw &&
this.props.metadata &&
this.props.metadata.nsfw
) {
this.setState({
showNsfwHelp: true,
});
}
}
handleMouseOut() {
if (this.state.showNsfwHelp) {
this.setState({
showNsfwHelp: false,
});
}
}
render() { render() {
const { const {
metadata, metadata,
@ -27,6 +51,7 @@ class Video extends React.PureComponent {
const { isPlaying = false } = this.state; const { isPlaying = false } = this.state;
const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0; const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const mediaType = lbry.getMediaType( const mediaType = lbry.getMediaType(
contentType, contentType,
fileInfo && fileInfo.file_name fileInfo && fileInfo.file_name
@ -47,6 +72,7 @@ class Video extends React.PureComponent {
} }
let klasses = []; let klasses = [];
klasses.push(obscureNsfw ? "video--obscured " : "");
if (isLoading || isDownloading) klasses.push("video-embedded", "video"); if (isLoading || isDownloading) klasses.push("video-embedded", "video");
if (mediaType === "video") { if (mediaType === "video") {
klasses.push("video-embedded", "video"); klasses.push("video-embedded", "video");
@ -59,7 +85,11 @@ class Video extends React.PureComponent {
const poster = metadata.thumbnail; const poster = metadata.thumbnail;
return ( return (
<div className={klasses.join(" ")}> <div
className={klasses.join(" ")}
onMouseEnter={this.handleMouseOver.bind(this)}
onMouseLeave={this.handleMouseOut.bind(this)}
>
{isPlaying && {isPlaying &&
(!isReadyToPlay (!isReadyToPlay
? <LoadingScreen status={loadStatusMessage} /> ? <LoadingScreen status={loadStatusMessage} />
@ -81,6 +111,7 @@ class Video extends React.PureComponent {
mediaType={mediaType} mediaType={mediaType}
/> />
</div>} </div>}
{this.state.showNsfwHelp && <NsfwOverlay />}
</div> </div>
); );
} }

View file

@ -323,7 +323,9 @@ lbry.getMediaType = function(contentType, fileName) {
return "video"; return "video";
} else if (/^mp3|m4a|aac|wav|flac|ogg|opus$/i.test(ext)) { } else if (/^mp3|m4a|aac|wav|flac|ogg|opus$/i.test(ext)) {
return "audio"; return "audio";
} else if (/^html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|org$/i.test(ext)) { } else if (
/^html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org$/i.test(ext)
) {
return "document"; return "document";
} else { } else {
return "unknown"; return "unknown";

View file

@ -10,6 +10,7 @@ import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
} from "selectors/claims"; } from "selectors/claims";
import { makeSelectCostInfoForUri } from "selectors/cost_info"; import { makeSelectCostInfoForUri } from "selectors/cost_info";
import { selectObscureNsfw } from "selectors/app";
import FilePage from "./view"; import FilePage from "./view";
const makeSelect = () => { const makeSelect = () => {
@ -24,6 +25,7 @@ const makeSelect = () => {
contentType: selectContentType(state, props), contentType: selectContentType(state, props),
costInfo: selectCostInfo(state, props), costInfo: selectCostInfo(state, props),
metadata: selectMetadata(state, props), metadata: selectMetadata(state, props),
obscureNsfw: selectObscureNsfw(state),
fileInfo: selectFileInfo(state, props), fileInfo: selectFileInfo(state, props),
}); });

View file

@ -81,6 +81,7 @@ class FilePage extends React.PureComponent {
const uriIndicator = <UriIndicator uri={uri} />; const uriIndicator = <UriIndicator uri={uri} />;
const mediaType = lbry.getMediaType(contentType); const mediaType = lbry.getMediaType(contentType);
const player = require("render-media"); const player = require("render-media");
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isPlayable = const isPlayable =
Object.values(player.mime).indexOf(contentType) !== -1 || Object.values(player.mime).indexOf(contentType) !== -1 ||
mediaType === "audio"; mediaType === "audio";
@ -94,7 +95,7 @@ class FilePage extends React.PureComponent {
? <Thumbnail src={metadata.thumbnail} /> ? <Thumbnail src={metadata.thumbnail} />
: <Thumbnail />} : <Thumbnail />}
</section> </section>
<section className="card"> <section className={"card " + (obscureNsfw ? "card--obscured " : "")}>
<div className="card__inner"> <div className="card__inner">
<div className="card__title-identity"> <div className="card__title-identity">
{!fileInfo || fileInfo.written_bytes <= 0 {!fileInfo || fileInfo.written_bytes <= 0

View file

@ -39,7 +39,7 @@ $box-shadow-focus: 2px 4px 4px 0 rgba(0,0,0,.14),2px 5px 3px -2px rgba(0,0,0,.2)
$transition-standard: .225s ease; $transition-standard: .225s ease;
$blur-intensity: 8px; $blur-intensity-nsfw: 20px;
@mixin clearfix() @mixin clearfix()
{ {

View file

@ -17,11 +17,7 @@ $padding-card-horizontal: $spacing-vertical * 2/3;
position: relative; position: relative;
} }
.card--obscured .card__inner { .card--obscured .card__inner {
-webkit-filter: blur($blur-intensity); filter: blur($blur-intensity-nsfw);
-moz-filter: blur($blur-intensity);
-o-filter: blur($blur-intensity);
-ms-filter: blur($blur-intensity);
filter: blur($blur-intensity);
} }
.card__title-primary { .card__title-primary {
padding: 0 $padding-card-horizontal; padding: 0 $padding-card-horizontal;

View file

@ -33,6 +33,11 @@ video {
transform: translateY(-50%); transform: translateY(-50%);
} }
} }
.video--obscured .video__cover
{
position: relative;
filter: blur($blur-intensity-nsfw);
}
.video__loading-screen { .video__loading-screen {