Compare commits

...

9 commits

Author SHA1 Message Date
Anthony
939be05e5d
working prototype 2021-10-12 19:02:11 +03:00
Anthony
85447185a8
enable show internal feature 2021-10-11 18:56:50 +03:00
Anthony
59a9f46c29
allow for embeds 2021-10-11 17:57:32 +03:00
Anthony
5b4151bc72
only run twenty percent of the time for unauthed users 2021-10-11 17:11:58 +03:00
Anthony
6c463e7310
bugfix and turn skip back on 2021-10-11 16:19:38 +03:00
Anthony
3afee8e5c9
improving documentation 2021-10-08 18:37:03 +03:00
Anthony
26fc53bb4d
point towards test server 2021-10-07 20:36:48 +03:00
Anthony
858d038c48
switch macro to aniview 2021-10-05 20:16:27 +03:00
Anthony
65994c4ebf
re enable preload ads 2021-10-05 20:05:43 +03:00
6 changed files with 117 additions and 56 deletions

View file

@ -240,7 +240,7 @@ const analytics: Analytics = {
startWatchmanIntervalIfNotRunning(); startWatchmanIntervalIfNotRunning();
} }
}, },
videoStartEvent: (claimId, duration, poweredBy, passedUserId, canonicalUrl, passedPlayer) => { videoStartEvent: (claimId, timeToStartVideo, poweredBy, passedUserId, canonicalUrl, passedPlayer) => {
// populate values for watchman when video starts // populate values for watchman when video starts
userId = passedUserId; userId = passedUserId;
claimUrl = canonicalUrl; claimUrl = canonicalUrl;
@ -249,8 +249,8 @@ const analytics: Analytics = {
videoType = passedPlayer.currentSource().type; videoType = passedPlayer.currentSource().type;
videoPlayer = passedPlayer; videoPlayer = passedPlayer;
sendPromMetric('time_to_start', duration); sendPromMetric('time_to_start', timeToStartVideo);
sendMatomoEvent('Media', 'TimeToStart', claimId, duration); sendMatomoEvent('Media', 'TimeToStart', claimId, timeToStartVideo);
}, },
error: (message) => { error: (message) => {
return new Promise((resolve) => { return new Promise((resolve) => {

View file

@ -327,19 +327,17 @@ function App(props: Props) {
// Load IMA3 SDK for aniview: DISABLED FOR NOW // Load IMA3 SDK for aniview: DISABLED FOR NOW
// @if TARGET='web' // @if TARGET='web'
// useEffect(() => { useEffect(() => {
// if (ENABLE_PREROLL_ADS) { const script = document.createElement('script');
// const script = document.createElement('script'); script.src = `https://imasdk.googleapis.com/js/sdkloader/ima3.js`;
// script.src = `https://imasdk.googleapis.com/js/sdkloader/ima3.js`; script.async = true;
// script.async = true; // $FlowFixMe
// // $FlowFixMe document.body.appendChild(script);
// document.body.appendChild(script); return () => {
// return () => { // $FlowFixMe
// // $FlowFixMe document.body.removeChild(script);
// document.body.removeChild(script); };
// }; });
// }
// });
// @endif // @endif
// @if TARGET='app' // @if TARGET='app'

View file

@ -30,9 +30,11 @@ const select = (state, props) => {
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const autoplay = urlParams.get('autoplay'); const autoplay = urlParams.get('autoplay');
const uri = props.uri; const uri = props.uri;
// TODO: eventually this should be received from DB and not local state (https://github.com/lbryio/lbry-desktop/issues/6796) // TODO: eventually this should be received from DB and not local state (https://github.com/lbryio/lbry-desktop/issues/6796)
const position = urlParams.get('t') !== null ? urlParams.get('t') : makeSelectContentPositionForUri(uri)(state); const position = urlParams.get('t') !== null ? urlParams.get('t') : makeSelectContentPositionForUri(uri)(state);
const userId = selectUser(state) && selectUser(state).id; const userId = selectUser(state) && selectUser(state).id;
const internalFeature = selectUser(state) && selectUser(state).internal_feature;
const playingUri = selectPlayingUri(state); const playingUri = selectPlayingUri(state);
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId); const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId);
const isMarkdownOrComment = playingUri && (playingUri.source === 'markdown' || playingUri.source === 'comment'); const isMarkdownOrComment = playingUri && (playingUri.source === 'markdown' || playingUri.source === 'comment');
@ -50,6 +52,7 @@ const select = (state, props) => {
return { return {
position, position,
userId, userId,
internalFeature,
collectionId, collectionId,
nextRecommendedUri, nextRecommendedUri,
previousListUri, previousListUri,

View file

@ -26,13 +26,19 @@ const VERSION = '0.0.1';
* */ * */
// TEST PRE-ROLL WITH THIS TAG: // TEST PRE-ROLL WITH THIS TAG:
// https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator= // const macroUrl = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator=';
// live channel
// b354389c7adb506d0bd9a4
// ford ad
// 612fb75a42715a07645a614c
// Modified to work with IMA // Modified to work with IMA
const macroUrl = const macroUrl =
`https://vast.aniview.com/api/adserver61/vast/` + `https://vast.aniview.com/api/adserver61/vast/` +
`?AV_PUBLISHERID=60afcbc58cfdb065440d2426` + `?AV_PUBLISHERID=60afcbc58cfdb065440d2426` +
`&AV_CHANNELID=60b354389c7adb506d0bd9a4` + `&AV_CHANNELID=612fb75a42715a07645a614c` +
`&AV_URL=[URL]` + `&AV_URL=[URL]` +
`&cb=[CACHEBUSTING]` + `&cb=[CACHEBUSTING]` +
`&AV_WIDTH=[WIDTH]` + `&AV_WIDTH=[WIDTH]` +
@ -45,7 +51,7 @@ const macroUrl =
`&skiptimer=5` + `&skiptimer=5` +
`&logo=true` + `&logo=true` +
`&usevslot=true` + `&usevslot=true` +
`&vastretry=5` + `&vastretry=2` +
`&hidecontrols=false`; `&hidecontrols=false`;
const defaults = { const defaults = {
@ -69,16 +75,16 @@ class AniviewPlugin extends Component {
this.player = player; this.player = player;
// request ads whenever there's new video content // request ads whenever there's new video content
/* player.on('contentchanged', () => { player.on('contentchanged', () => {
// in a real plugin, you might fetch your ad inventory here // in a real plugin, you might fetch your ad inventory here
player.trigger('adsready'); player.trigger('adsready');
}); */ });
// Plugin event listeners // Plugin event listeners
// player.on('readyforpreroll', (event) => this.onReadyForPreroll(event)); player.on('readyforpreroll', (event) => this.onReadyForPreroll(event));
} }
/* onReadyForPreroll(event) { onReadyForPreroll(event) {
// send event when ad is playing to remove loading spinner // send event when ad is playing to remove loading spinner
this.player.one('adplaying', () => { this.player.one('adplaying', () => {
this.player.trigger('ads-ad-started'); this.player.trigger('ads-ad-started');
@ -88,7 +94,7 @@ class AniviewPlugin extends Component {
this.player.one('adended', () => { this.player.one('adended', () => {
this.player.ads.endLinearAdMode(); this.player.ads.endLinearAdMode();
}); });
} */ }
log(...args) { log(...args) {
if (this.options_.debug) { if (this.options_.debug) {

View file

@ -16,7 +16,7 @@ import qualityLevels from 'videojs-contrib-quality-levels';
import isUserTyping from 'util/detect-typing'; import isUserTyping from 'util/detect-typing';
// @if TARGET='web' // @if TARGET='web'
// Disabled for now. // Disabled for now.
// import './plugins/videojs-aniview/plugin'; import './plugins/videojs-aniview/plugin';
// @endif // @endif
const isDev = process.env.NODE_ENV !== 'production'; const isDev = process.env.NODE_ENV !== 'production';
@ -60,7 +60,8 @@ type Props = {
adUrl: ?string, adUrl: ?string,
claimId: ?string, claimId: ?string,
userId: ?number, userId: ?number,
// allowPreRoll: ?boolean, allowPreRoll: ?boolean,
internalFeatureEnabled: ?boolean,
shareTelemetry: boolean, shareTelemetry: boolean,
replay: boolean, replay: boolean,
videoTheaterMode: boolean, videoTheaterMode: boolean,
@ -77,6 +78,30 @@ type Props = {
// muted?: boolean, // muted?: boolean,
// }; // };
function hitsTwentyPercent() {
// from 0 - 999
var rand = Math.floor(Math.random() * (1000 + 1));
console.log(rand);
console.log('rand');
setTimeout(function(){
console.log('play here');
player.play()
}, 1000)
return true
if (rand > 799) {
return true;
} else {
return false;
}
}
const videoPlaybackRates = [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 1.75, 2]; const videoPlaybackRates = [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 1.75, 2];
const IS_IOS = const IS_IOS =
@ -178,7 +203,8 @@ export default React.memo<Props>(function VideoJs(props: Props) {
adUrl, adUrl,
claimId, claimId,
userId, userId,
// allowPreRoll, allowPreRoll,
internalFeatureEnabled,
shareTelemetry, shareTelemetry,
replay, replay,
videoTheaterMode, videoTheaterMode,
@ -539,6 +565,14 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// this seems like a weird thing to have to check for here // this seems like a weird thing to have to check for here
if (!player) return; if (!player) return;
// always have ads on if internal feature is on,
// otherwise if not authed, roll for 20% to see an ad
const shouldShowAnAd = internalFeatureEnabled || (allowPreRoll && hitsTwentyPercent());
if (shouldShowAnAd) {
vjs.aniview();
}
// Add various event listeners to player // Add various event listeners to player
player.one('play', onInitialPlay); player.one('play', onInitialPlay);
player.on('play', resolveCtrlText); player.on('play', resolveCtrlText);
@ -579,6 +613,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// I think this is a callback function // I think this is a callback function
const videoNode = containerRef.current && containerRef.current.querySelector('video, audio'); const videoNode = containerRef.current && containerRef.current.querySelector('video, audio');
onPlayerReady(player, videoNode); onPlayerReady(player, videoNode);
}); });

View file

@ -55,6 +55,7 @@ type Props = {
setVideoPlaybackRate: (number) => void, setVideoPlaybackRate: (number) => void,
authenticated: boolean, authenticated: boolean,
userId: number, userId: number,
internalFeature: boolean,
homepageData?: { [string]: HomepageCat }, homepageData?: { [string]: HomepageCat },
shareTelemetry: boolean, shareTelemetry: boolean,
isFloating: boolean, isFloating: boolean,
@ -98,6 +99,7 @@ function VideoViewer(props: Props) {
homepageData, homepageData,
authenticated, authenticated,
userId, userId,
internalFeature,
shareTelemetry, shareTelemetry,
isFloating, isFloating,
doPlayUri, doPlayUri,
@ -152,6 +154,7 @@ function VideoViewer(props: Props) {
}; };
}, [embedded, videoPlaybackRate]); }, [embedded, videoPlaybackRate]);
// TODO: analytics functionality
function doTrackingBuffered(e: Event, data: any) { function doTrackingBuffered(e: Event, data: any) {
fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => { fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => {
data.playerPoweredBy = response.headers.get('x-powered-by'); data.playerPoweredBy = response.headers.get('x-powered-by');
@ -159,21 +162,37 @@ function VideoViewer(props: Props) {
}); });
} }
/**
* Analytics functionality that is run on first video start
* @param e - event from videojs (from the plugin?)
* @param data - only has secondsToLoad property
*/
function doTrackingFirstPlay(e: Event, data: any) { function doTrackingFirstPlay(e: Event, data: any) {
let timeToStart = data.secondsToLoad; // how long until the video starts
let timeToStartVideo = data.secondsToLoad;
// TODO: what's happening here briefly?
if (!IS_WEB) {
if (desktopPlayStartTime !== undefined) { if (desktopPlayStartTime !== undefined) {
const differenceToAdd = Date.now() - desktopPlayStartTime; const differenceToAdd = Date.now() - desktopPlayStartTime;
timeToStart += differenceToAdd; timeToStartVideo += differenceToAdd;
} }
}
// send matomo event (embedded is boolean)
analytics.playerStartedEvent(embedded); analytics.playerStartedEvent(embedded);
// figure out what server the video is served from and then run start analytic event
fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => { fetch(source, { method: 'HEAD', cache: 'no-store' }).then((response) => {
// server string such as 'eu-p6'
let playerPoweredBy = response.headers.get('x-powered-by') || ''; let playerPoweredBy = response.headers.get('x-powered-by') || '';
analytics.videoStartEvent(claimId, timeToStart, playerPoweredBy, userId, claim.canonical_url, this);
// populates data for watchman, sends prom and matomo event
analytics.videoStartEvent(claimId, timeToStartVideo, playerPoweredBy, userId, claim.canonical_url, this);
}); });
doAnalyticsView(uri, timeToStart).then(() => { // hit backend to mark a view
doAnalyticsView(uri, timeToStartVideo).then(() => {
claimRewards(); claimRewards();
}); });
} }
@ -256,6 +275,7 @@ function VideoViewer(props: Props) {
clearPosition(uri); clearPosition(uri);
}, [adUrl, autoplayNext, clearPosition, collectionId, embedded, ended, setAdUrl, uri]); }, [adUrl, autoplayNext, clearPosition, collectionId, embedded, ended, setAdUrl, uri]);
// MORE ON PLAY STUFF
function onPlay(player) { function onPlay(player) {
setEnded(false); setEnded(false);
setIsLoading(false); setIsLoading(false);
@ -436,7 +456,6 @@ function VideoViewer(props: Props) {
</> </>
)} )}
{!isFetchingAd && (
<VideoJs <VideoJs
adUrl={adUrl} adUrl={adUrl}
source={adUrl || source} source={adUrl || source}
@ -450,7 +469,8 @@ function VideoViewer(props: Props) {
autoplaySetting={autoplayNext} autoplaySetting={autoplayNext}
claimId={claimId} claimId={claimId}
userId={userId} userId={userId}
allowPreRoll={!embedded && !authenticated} allowPreRoll={!authenticated} // used to not include embeds, removed for now
internalFeatureEnabled={internalFeature}
shareTelemetry={shareTelemetry} shareTelemetry={shareTelemetry}
replay={replay} replay={replay}
videoTheaterMode={videoTheaterMode} videoTheaterMode={videoTheaterMode}
@ -458,7 +478,6 @@ function VideoViewer(props: Props) {
playPrevious={doPlayPrevious} playPrevious={doPlayPrevious}
embedded={embedded} embedded={embedded}
/> />
)}
</div> </div>
); );
} }