initial commit for inline video ads
This commit is contained in:
parent
829c2eac50
commit
c4fc2993d5
12 changed files with 162 additions and 67 deletions
|
@ -4,28 +4,49 @@ import React, { useEffect } from 'react';
|
|||
import { withRouter } from 'react-router';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import Button from 'component/button';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const ADS_URL = '//assets.revcontent.com/master/delivery.js';
|
||||
const IS_MOBILE = typeof window.orientation !== 'undefined';
|
||||
|
||||
type Props = {
|
||||
location: { pathname: string },
|
||||
type: string,
|
||||
small: boolean,
|
||||
};
|
||||
|
||||
function Ads(props: Props) {
|
||||
const {
|
||||
location: { pathname },
|
||||
type = 'sidebar',
|
||||
small,
|
||||
} = props;
|
||||
useEffect(() => {
|
||||
if (!IS_MOBILE) {
|
||||
const script = document.createElement('script');
|
||||
|
||||
useEffect(() => {
|
||||
if (type === 'video') {
|
||||
try {
|
||||
const d = document;
|
||||
const s = 'script';
|
||||
const n = 'playbuzz-stream';
|
||||
|
||||
let js;
|
||||
let fjs = d.getElementsByTagName(s)[0];
|
||||
js = d.createElement(s);
|
||||
js.className = n;
|
||||
js.src = 'https://stream.playbuzz.com/player/62d1eb10-e362-4873-99ed-c64a4052b43b';
|
||||
// $FlowFixMe
|
||||
fjs.parentNode.inmodifiedUrlQuerysertBefore(js, fjs);
|
||||
} catch (e) {}
|
||||
}
|
||||
}, [type]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!IS_MOBILE && type === 'sidebar') {
|
||||
const script = document.createElement('script');
|
||||
script.src = ADS_URL;
|
||||
script.async = true;
|
||||
|
||||
// $FlowFixMe
|
||||
document.body.appendChild(script);
|
||||
|
||||
return () => {
|
||||
// $FlowFixMe
|
||||
document.body.removeChild(script);
|
||||
|
@ -37,27 +58,37 @@ function Ads(props: Props) {
|
|||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
const adsSignInDriver = (
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
sign_in_to_lbrytv: (
|
||||
<Button button="link" label={__('Sign in to lbry.tv')} navigate={`/$/${PAGES.AUTH}?redirect=${pathname}`} />
|
||||
),
|
||||
download_the_app: <Button button="link" label={__('download the app')} href="https://lbry.com/get" />,
|
||||
}}
|
||||
>
|
||||
Hate these? %sign_in_to_lbrytv% or %download_the_app% for an ad free experience.
|
||||
</I18nMessage>
|
||||
);
|
||||
|
||||
return type === 'video' ? (
|
||||
<div className="ads__claim-item">
|
||||
<div id="62d1eb10-e362-4873-99ed-c64a4052b43b" />
|
||||
<div
|
||||
className={classnames('ads__claim-text', {
|
||||
'ads__claim-text--small': small,
|
||||
})}
|
||||
>
|
||||
<div>Ad</div>
|
||||
<p>{adsSignInDriver}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="ads-wrapper">
|
||||
<p>Ads</p>
|
||||
<p>
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
sign_in_to_lbrytv: (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Sign in to lbry.tv')}
|
||||
navigate={`/$/${PAGES.AUTH}?redirect=${pathname}`}
|
||||
/>
|
||||
),
|
||||
download_the_app: <Button button="link" label={__('download the app')} href="https://lbry.com/get" />,
|
||||
}}
|
||||
>
|
||||
Hate these? %sign_in_to_lbrytv% or %download_the_app% for an ad free experience.
|
||||
</I18nMessage>
|
||||
</p>
|
||||
<p>{adsSignInDriver}</p>
|
||||
<div
|
||||
id="rc-widget-0a74cf"
|
||||
data-rc-widget
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
makeSelectClaimForUri,
|
||||
} from 'lbry-redux';
|
||||
import { withRouter } from 'react-router';
|
||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||
import ChannelPage from './view';
|
||||
|
||||
const select = (state, props) => {
|
||||
|
@ -23,6 +24,7 @@ const select = (state, props) => {
|
|||
channelIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
channelIsBlocked: selectChannelIsBlocked(props.uri)(state),
|
||||
claim: props.uri && makeSelectClaimForUri(props.uri)(state),
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -30,9 +32,4 @@ const perform = dispatch => ({
|
|||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||
});
|
||||
|
||||
export default withRouter(
|
||||
connect(
|
||||
select,
|
||||
perform
|
||||
)(ChannelPage)
|
||||
);
|
||||
export default withRouter(connect(select, perform)(ChannelPage));
|
||||
|
|
|
@ -5,6 +5,7 @@ import { withRouter } from 'react-router-dom';
|
|||
import Button from 'component/button';
|
||||
import ClaimListDiscover from 'component/claimListDiscover';
|
||||
import * as CS from 'constants/claim_search';
|
||||
import Ads from 'lbrytv/component/ads';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -17,10 +18,11 @@ type Props = {
|
|||
fetchClaims: (string, number) => void,
|
||||
channelIsBlackListed: boolean,
|
||||
claim: ?Claim,
|
||||
isAuthenticated: boolean,
|
||||
};
|
||||
|
||||
function ChannelContent(props: Props) {
|
||||
const { uri, fetching, channelIsMine, channelIsBlocked, channelIsBlackListed, claim } = props;
|
||||
const { uri, fetching, channelIsMine, channelIsBlocked, channelIsBlackListed, claim, isAuthenticated } = props;
|
||||
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
||||
|
||||
return (
|
||||
|
@ -51,7 +53,11 @@ function ChannelContent(props: Props) {
|
|||
{!channelIsMine && claimsInChannel > 0 && <HiddenNsfwClaims uri={uri} />}
|
||||
|
||||
{claim && claimsInChannel > 0 ? (
|
||||
<ClaimListDiscover channelIds={[claim.claim_id]} defaultOrderBy={CS.ORDER_BY_NEW} />
|
||||
<ClaimListDiscover
|
||||
channelIds={[claim.claim_id]}
|
||||
defaultOrderBy={CS.ORDER_BY_NEW}
|
||||
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" />}
|
||||
/>
|
||||
) : (
|
||||
<section className="main--empty">This channel hasn't published anything yet</section>
|
||||
)}
|
||||
|
|
|
@ -31,6 +31,7 @@ type Props = {
|
|||
renderProperties: ?(Claim) => Node,
|
||||
includeSupportAction?: boolean,
|
||||
hideBlock: boolean,
|
||||
injectedItem: ?Node,
|
||||
};
|
||||
|
||||
export default function ClaimList(props: Props) {
|
||||
|
@ -53,6 +54,7 @@ export default function ClaimList(props: Props) {
|
|||
renderProperties,
|
||||
includeSupportAction,
|
||||
hideBlock,
|
||||
injectedItem,
|
||||
} = props;
|
||||
const [scrollBottomCbMap, setScrollBottomCbMap] = useState({});
|
||||
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
|
||||
|
@ -130,26 +132,28 @@ export default function ClaimList(props: Props) {
|
|||
{urisLength > 0 && (
|
||||
<ul className="card ul--no-style">
|
||||
{sortedUris.map((uri, index) => (
|
||||
<ClaimPreview
|
||||
key={uri}
|
||||
uri={uri}
|
||||
type={type}
|
||||
includeSupportAction={includeSupportAction}
|
||||
showUnresolvedClaim={showUnresolvedClaims}
|
||||
properties={renderProperties || (type !== 'small' ? undefined : false)}
|
||||
showUserBlocked={showHiddenByUser}
|
||||
hideBlock={hideBlock}
|
||||
customShouldHide={(claim: StreamClaim) => {
|
||||
// Hack to hide spee.ch thumbnail publishes
|
||||
// If it meets these requirements, it was probably uploaded here:
|
||||
// https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79
|
||||
if (claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<React.Fragment key={uri}>
|
||||
{injectedItem && index === 4 && <li>{injectedItem}</li>}
|
||||
<ClaimPreview
|
||||
uri={uri}
|
||||
type={type}
|
||||
includeSupportAction={includeSupportAction}
|
||||
showUnresolvedClaim={showUnresolvedClaims}
|
||||
properties={renderProperties || (type !== 'small' ? undefined : false)}
|
||||
showUserBlocked={showHiddenByUser}
|
||||
hideBlock={hideBlock}
|
||||
customShouldHide={(claim: StreamClaim) => {
|
||||
// Hack to hide spee.ch thumbnail publishes
|
||||
// If it meets these requirements, it was probably uploaded here:
|
||||
// https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79
|
||||
if (claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
|
|
@ -52,6 +52,7 @@ type Props = {
|
|||
repostedClaimId?: string,
|
||||
pageSize?: number,
|
||||
followedTags?: Array<Tag>,
|
||||
injectedItem: ?Node,
|
||||
};
|
||||
|
||||
function ClaimListDiscover(props: Props) {
|
||||
|
@ -87,6 +88,7 @@ function ClaimListDiscover(props: Props) {
|
|||
repostedClaimId,
|
||||
hideFilter,
|
||||
followedTags,
|
||||
injectedItem,
|
||||
} = props;
|
||||
const didNavigateForward = history.action === 'PUSH';
|
||||
const { search } = location;
|
||||
|
@ -596,6 +598,7 @@ function ClaimListDiscover(props: Props) {
|
|||
renderProperties={renderProperties}
|
||||
includeSupportAction={includeSupportAction}
|
||||
hideBlock={hideBlock}
|
||||
injectedItem={injectedItem}
|
||||
/>
|
||||
|
||||
{loading && (
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
makeSelectRecommendedContentForUri,
|
||||
selectIsSearching,
|
||||
} from 'lbry-redux';
|
||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||
import RecommendedVideos from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
@ -13,13 +14,11 @@ const select = (state, props) => ({
|
|||
mature: makeSelectClaimIsNsfw(props.uri)(state),
|
||||
recommendedContent: makeSelectRecommendedContentForUri(props.uri)(state),
|
||||
isSearching: selectIsSearching(state),
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
search: (query, options) => dispatch(doSearch(query, options)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(RecommendedVideos);
|
||||
export default connect(select, perform)(RecommendedVideos);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import ClaimList from 'component/claimList';
|
||||
import Ads from 'lbrytv/component/ads';
|
||||
|
||||
type Options = {
|
||||
related_to: string,
|
||||
|
@ -15,6 +16,7 @@ type Props = {
|
|||
isSearching: boolean,
|
||||
search: (string, Options) => void,
|
||||
mature: boolean,
|
||||
isAuthenticated: boolean,
|
||||
};
|
||||
|
||||
export default class RecommendedContent extends React.PureComponent<Props> {
|
||||
|
@ -59,13 +61,14 @@ export default class RecommendedContent extends React.PureComponent<Props> {
|
|||
didSearch: ?boolean;
|
||||
|
||||
render() {
|
||||
const { recommendedContent, isSearching } = this.props;
|
||||
const { recommendedContent, isSearching, isAuthenticated } = this.props;
|
||||
|
||||
return (
|
||||
<ClaimList
|
||||
type="small"
|
||||
loading={isSearching}
|
||||
uris={recommendedContent}
|
||||
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" small />}
|
||||
header={__('Related')}
|
||||
empty={__('No related content found')}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectClaimForUri, selectFollowedTags, doResolveUri } from 'lbry-redux';
|
||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||
import { doToggleTagFollowDesktop } from 'redux/actions/tags';
|
||||
import * as CS from 'constants/claim_search';
|
||||
import Tags from './view';
|
||||
|
@ -13,6 +14,7 @@ const select = (state, props) => {
|
|||
followedTags: selectFollowedTags(state),
|
||||
repostedUri: repostedUri,
|
||||
repostedClaim: repostedUri ? makeSelectClaimForUri(repostedUri)(state) : null,
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import analytics from 'analytics';
|
|||
import HiddenNsfw from 'component/common/hidden-nsfw';
|
||||
import Icon from 'component/common/icon';
|
||||
import * as CS from 'constants/claim_search';
|
||||
import Ads from 'lbrytv/component/ads';
|
||||
|
||||
type Props = {
|
||||
location: { search: string },
|
||||
|
@ -17,6 +18,7 @@ type Props = {
|
|||
repostedClaim: ?GenericClaim,
|
||||
doToggleTagFollowDesktop: string => void,
|
||||
doResolveUri: string => void,
|
||||
isAuthenticated: boolean,
|
||||
};
|
||||
|
||||
function DiscoverPage(props: Props) {
|
||||
|
@ -27,6 +29,7 @@ function DiscoverPage(props: Props) {
|
|||
repostedUri,
|
||||
doToggleTagFollowDesktop,
|
||||
doResolveUri,
|
||||
isAuthenticated,
|
||||
} = props;
|
||||
const buttonRef = useRef();
|
||||
const isHovering = useHover(buttonRef);
|
||||
|
@ -89,6 +92,7 @@ function DiscoverPage(props: Props) {
|
|||
tags={tags}
|
||||
hiddenNsfwMessage={<HiddenNsfw type="page" />}
|
||||
repostedClaimId={repostedClaim ? repostedClaim.claim_id : null}
|
||||
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" />}
|
||||
meta={
|
||||
tag && (
|
||||
<Button
|
||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import { doSearch, selectIsSearching, makeSelectSearchUris, makeSelectQueryWithOptions, doToast } from 'lbry-redux';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { selectUserVerifiedEmail } from 'lbryinc';
|
||||
import analytics from 'analytics';
|
||||
import SearchPage from './view';
|
||||
|
||||
|
@ -17,6 +18,7 @@ const select = state => {
|
|||
isSearching: selectIsSearching(state),
|
||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||
uris: uris,
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -42,7 +44,4 @@ const perform = dispatch => ({
|
|||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(SearchPage);
|
||||
export default connect(select, perform)(SearchPage);
|
||||
|
|
|
@ -9,6 +9,7 @@ import Page from 'component/page';
|
|||
import SearchOptions from 'component/searchOptions';
|
||||
import Button from 'component/button';
|
||||
import ClaimUri from 'component/claimUri';
|
||||
import Ads from 'lbrytv/component/ads';
|
||||
|
||||
type AdditionalOptions = {
|
||||
isBackgroundSearch: boolean,
|
||||
|
@ -23,10 +24,20 @@ type Props = {
|
|||
onFeedbackNegative: string => void,
|
||||
onFeedbackPositive: string => void,
|
||||
showNsfw: boolean,
|
||||
isAuthenticated: boolean,
|
||||
};
|
||||
|
||||
export default function SearchPage(props: Props) {
|
||||
const { search, uris, onFeedbackPositive, onFeedbackNegative, location, isSearching, showNsfw } = props;
|
||||
const {
|
||||
search,
|
||||
uris,
|
||||
onFeedbackPositive,
|
||||
onFeedbackNegative,
|
||||
location,
|
||||
isSearching,
|
||||
showNsfw,
|
||||
isAuthenticated,
|
||||
} = props;
|
||||
const urlParams = new URLSearchParams(location.search);
|
||||
const urlQuery = urlParams.get('q') || '';
|
||||
const additionalOptions: AdditionalOptions = { isBackgroundSearch: false };
|
||||
|
@ -44,12 +55,13 @@ export default function SearchPage(props: Props) {
|
|||
isValid = false;
|
||||
}
|
||||
|
||||
const modifiedUrlQuery = isValid
|
||||
? path
|
||||
: urlQuery
|
||||
.trim()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(INVALID_URI_CHARS, '');
|
||||
const modifiedUrlQuery =
|
||||
isValid && path
|
||||
? path
|
||||
: urlQuery
|
||||
.trim()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(INVALID_URI_CHARS, '');
|
||||
const uriFromQuery = `lbry://${modifiedUrlQuery}`;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -85,6 +97,7 @@ export default function SearchPage(props: Props) {
|
|||
uris={uris}
|
||||
loading={isSearching}
|
||||
header={<SearchOptions additionalOptions={additionalOptions} />}
|
||||
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" />}
|
||||
headerAltControls={
|
||||
<Fragment>
|
||||
<span>{__('Find what you were looking for?')}</span>
|
||||
|
|
|
@ -14,3 +14,37 @@
|
|||
color: var(--color-ads-link);
|
||||
}
|
||||
}
|
||||
|
||||
// Inline Video Ads
|
||||
.ads__claim-item {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: var(--spacing-medium);
|
||||
background-color: var(--color-ads-background);
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
width: 50%;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.avp-p-gui {
|
||||
z-index: 1 !important;
|
||||
}
|
||||
|
||||
.pbs__player.pb-stream-sticky-on {
|
||||
position: relative !important;
|
||||
z-index: 1 !important;
|
||||
margin-top: -140px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ads__claim-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-left: var(--spacing-large);
|
||||
}
|
||||
|
||||
.ads__claim-text--small {
|
||||
font-size: var(--font-small);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue