lbry-desktop/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js

178 lines
4.8 KiB
JavaScript

// Created by xander on 6/21/2021
import videojs from 'video.js';
import RecSys from 'extras/recsys/recsys';
const VERSION = '0.0.1';
/* RecSys */
const PlayerEvent = {
event: {
start: 0, // event types
stop: 1,
scrub: 2,
speed: 3,
},
};
function newRecsysPlayerEvent(eventType, offset, arg) {
if (arg) {
return {
event: eventType,
offset: offset,
arg: arg,
};
} else {
return {
event: eventType,
offset: offset,
};
}
}
const defaults = {
videoId: null,
userId: 0,
debug: false,
embedded: false,
};
const Component = videojs.getComponent('Component');
const registerPlugin = videojs.registerPlugin || videojs.plugin;
class RecsysPlugin extends Component {
constructor(player, options) {
super(player, options);
// Plugin started
if (options.debug) {
this.log(`Created recsys plugin for: videoId:${options.videoId}`);
}
// To help with debugging, we'll add a global vjs object with the video js player
window.vjs = player;
this.player = player;
this.lastTimeUpdate = null;
this.currentTimeUpdate = null;
this.inPause = false;
// Plugin event listeners
player.on('playing', (event) => this.onPlay(event));
player.on('pause', (event) => this.onPause(event));
player.on('ended', (event) => this.onEnded(event));
player.on('ratechange', (event) => this.onRateChange(event));
player.on('timeupdate', (event) => this.onTimeUpdate(event));
player.on('seeked', (event) => this.onSeeked(event));
// Event trigger to send recsys event
player.on('dispose', (event) => this.onDispose(event));
}
onPlay(event) {
const recsysEvent = newRecsysPlayerEvent(PlayerEvent.event.start, this.player.currentTime());
this.log('onPlay', recsysEvent);
RecSys.onRecsysPlayerEvent(this.options_.videoId, recsysEvent, this.options_.embedded);
this.inPause = false;
this.lastTimeUpdate = recsysEvent.offset;
}
onPause(event) {
const recsysEvent = newRecsysPlayerEvent(PlayerEvent.event.stop, this.player.currentTime());
this.log('onPause', recsysEvent);
RecSys.onRecsysPlayerEvent(this.options_.videoId, recsysEvent);
this.inPause = true;
}
onEnded(event) {
const recsysEvent = newRecsysPlayerEvent(PlayerEvent.event.stop, this.player.currentTime());
this.log('onEnded', recsysEvent);
RecSys.onRecsysPlayerEvent(this.options_.videoId, recsysEvent);
}
onRateChange(event) {
const recsysEvent = newRecsysPlayerEvent(
PlayerEvent.event.speed,
this.player.currentTime(),
this.player.playbackRate()
);
this.log('onRateChange', recsysEvent);
RecSys.onRecsysPlayerEvent(this.options_.videoId, recsysEvent);
}
onTimeUpdate(event) {
const nextCurrentTime = this.player.currentTime();
if (!this.inPause && Math.abs(this.lastTimeUpdate - nextCurrentTime) < 0.5) {
// Don't update lastTimeUpdate if we are in a pause segment.
//
// However, if we aren't in a pause and the time jumped
// the onTimeUpdate event probably fired before the pause and seek.
// Don't update in that case, either.
this.lastTimeUpdate = this.currentTimeUpdate;
}
this.currentTimeUpdate = nextCurrentTime;
}
onSeeked(event) {
const curTime = this.player.currentTime();
// There are three patterns for seeking:
//
// Assuming the video is playing,
//
// 1. Dragging the player head emits: onPause -> onSeeked -> onSeeked -> ... -> onPlay
// 2. Key press left right emits: onSeeked -> onPlay
// 3. Clicking a position emits: onPause -> onSeeked -> onPlay
//
// If the video is NOT playing,
//
// 1. Dragging the player head emits: onSeeked
// 2. Key press left right emits: onSeeked
// 3. Clicking a position emits: onSeeked
const fromTime = this.lastTimeUpdate;
if (fromTime !== curTime) {
// This removes duplicates that aren't useful.
const recsysEvent = newRecsysPlayerEvent(PlayerEvent.event.scrub, fromTime, curTime);
this.log('onSeeked', recsysEvent);
RecSys.onRecsysPlayerEvent(this.options_.videoId, recsysEvent);
}
}
onDispose(event) {
RecSys.onPlayerDispose(this.options_.videoId, this.options_.embedded);
}
log(...args) {
if (this.options_.debug) {
console.log(`Recsys Player Debug:`, JSON.stringify(args));
}
}
}
videojs.registerComponent('recsys', RecsysPlugin);
const onPlayerReady = (player, options) => {
player.recsys = new RecsysPlugin(player, options);
};
/**
* Initialize the plugin.
*
* @function plugin
* @param {Object} [options={}]
*/
const plugin = function (options) {
this.ready(() => {
onPlayerReady(this, videojs.mergeOptions(defaults, options));
});
};
plugin.VERSION = VERSION;
registerPlugin('recsys', plugin);
export default plugin;