Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
empanalytics-dev
Advanced tools
Analytics is now served as a standalone service and you can integrate this component into any javascript-based project other than the empPlayer. Android/iOS libraries already send analytics by themselves. Also, for the empPlayer, analytics are sent automa
Analytics is now served as a standalone service and you can integrate this component into any javascript-based project other than the empPlayer. Android/iOS libraries already send analytics by themselves. Also, for the empPlayer, analytics are sent automatically aswell. If your project is using an old analytics setup: for instance via plugin or calling the method setAnalytics, you can remove that code from your project as it is no longer necessary. Being a standalone component, EMPAnalytics can now be integrated with more products other than EMPPlayer. This tutorial will show you how to use EMP Analytics. When using the new component, please do not forget to remove the old video.js analytics plugin from your setup, otherwise the EMPPlayer might send duplicated analytics events. The new analytics service is delivered with some important bug fixes. We will no longer deliver new features or bug fixes to the old video.js analytics plugin.
This component collects playback events and sends them every 3s to EMP Exposure backend. In case no event has been generated and a playback is taking place, a Heartbeat event is sent every 60 seconds.
EMP-9815 adding 'referenceTime' as a parameter property to 'playing' method EMP-8869 detecting device clock change and resyncing with backend
The following configuration values are required when the plugin is created:
If you use the EntitlmentEngine provided by EMP, in order to have analytics, all you have to do is pass these values in as options when instantiating the player:
var exposureOptions = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
};
var options = {
'ericssonexposure': exposureOptions,
//...
}
If you use your own entitlment engine, just include these properties directly as options in your entitlement engine:
yourEMPPlayerObjec.entitlementEngine_.options_ = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
}
// This method is called to initialize the component.
init();
// This method is called to clear all pending analytics events.
clear();
// This property is called to enable/disable debug.
debug = true | false;
// This method is called to add an event for a new plackback
var params = {
autoplay: true // default: false
};
created(sessionId, params);
// This method is called when a 'play' command occurs (automatic or user triggered)
var params = {
techName: TECH_NAME, // default: false
version: TECH_VERSION,
deviceAppInfo: APP_INFO_STRING // optional
};
play(sessionId, startTime, params);
// This method is called when the media is actually playing
var params = {
bitrate: BITRATE_IN_BYTES,
duration: DURATION_IN_SECONDS,
mediaLocator: MEDIA_URL // optional (.mpd URL p.e.)
referenceTime: UNIX_TIME_OF_THE_BEGINNING_OF_STREAM_IN_MS // optional
};
playing(sessionId, currentTime, params);
// This method is called when the playback is paused.
paused(sessionId, currentTime);
// This method is called when a seek occurs.
seek(sessionId, seekTime);
// This method is called when the player starts casting to an external device (chromecast p.e.).
startCasting(sessionId, nowTime);
// This method is called when the player stops casting to an external device.
stopCasting(sessionId, nowTime);
// This method should be called regularly to update the playback current time.
setCurrentTime(sessionId, nowTime);
// This method is called when a new asset is loaded.
var params = {
assetId: EMP_ASSET_ID,
programId: EMP_PROGRAM_ID // optional
};
handshake(sessionId, params);
// This method is called when the playback is resumed from a paused state.
resume(sessionId, startTime, params);
// This method is called when there is a change in the playback bitrate.
var params = {
bitrate: BITRATE_IN_BYTES
};
bitrateChanged(sessionId, nowTime, params);
// This method is called when the playback plays all the media to the end.
endOfStream(sessionId, params = {});
// This method is called when an error occurs during a playback.
var params = {
errorCode: ERROR_CODE, // default: N/A
errorMessage: ERROR_MESSAGE // default: Unknown Error
};
error(sessionId, nowTime, params = {});
// This method is called when a user exits/disposes a playback before it reaches the end of the stream.
dispose(sessionId, nowTime, params = {});
// This method is called when the player enters goest into a waiting/buffering/loading state.
waiting(sessionId, nowTime, params = {});
// This method is called when the player leaves a waiting/buffering/loading state.
waitingEnded(sessionId, nowTime, params = {});
// This getter returns the current state of an analytics session (IDLE, PLAYING, DIRTY, FINISHED).
getSessionState(sessionId);
// This method immediately dispatches all events waiting to be sent to the backend.
dispatchNow(asyncCall = true);
// This method automatically disposes ongoing analytics session
exitOngoingSession(nowTime);
// This method allows you to register a custom attribute that will be sent on every Playback.Started event
setCustomAttribute(key, value);
// This method allows you to clear all custom events previously registered
clearCustomAttributes();
index.html
<html>
<head>
<script src="emp-analytics.min.js"></script>
<script src="html5player-analytics-connector.js"></script>
</head>
<body>
<video id="sample-video" autoplay>
<source src=http://techslides.com/demos/sample-videos/small.webm type=video/webm>
<source src=http://techslides.com/demos/sample-videos/small.ogv type=video/ogg>
<source src=http://techslides.com/demos/sample-videos/small.mp4 type=video/mp4>
<source src=http://techslides.com/demos/sample-videos/small.3gp type=video/3gp>
</video>
<script>
// Global variables
var SERVER_URL = 'YOUR_ANALYTICS_SERVER_URL';
var CUSTOMER = 'YOUR_CUSTOMER';
var BUSINESS_UNIT = 'YOUR_BUSINESS_UNIT';
var SESSION_TOKEN = 'YOUR_SESSION_TOKEN';
// Video element to connect analytics to
var html5player = document.getElementById('sample-video');
// Creating and initiating the analytics service
var analytics = new empAnalytics (SERVER_URL, CUSTOMER, BUSINESS_UNIT, SESSION_TOKEN);
analytics.init();
// Creating and initiating the connector - the constructor receives the html5 player element and the analytics component
var connector = new HTML5PlayerAnalyticsConnector(html5player, analytics);
connector.init();
</script>
</body>
</html>
html5player-analytics-connector.js
var HTML5PlayerAnalyticsConnector = function(html5player, analytics) {
this.player_ = html5player;
this.analytics_ = analytics;
this.onLoadStartBind = this.onLoadStart.bind(this);
this.onCanPlayBind = this.onCanPlay.bind(this);
this.onPlayingBind = this.onPlaying.bind(this);
this.onEndedBind = this.onEnded.bind(this);
this.onPauseBind = this.onPause.bind(this);
this.onSeekedBind = this.onSeeked.bind(this);
this.onErrorBind = this.onError.bind(this);
this.onAbortBind = this.onAbort.bind(this);
this.onWindowUnloadBind = this.onWindowUnload.bind(this);
this.init();
};
// Initialization function - adds events to the provided player
HTML5PlayerAnalyticsConnector.prototype.init = function() {
this.dispose();
this.rnd_ = Math.random();
this.player_.addEventListener('loadstart', this.onLoadStartBind);
this.player_.addEventListener('canplay', this.onCanPlayBind);
this.player_.addEventListener('playing', this.onPlayingBind);
this.player_.addEventListener('ended', this.onEndedBind);
this.player_.addEventListener('pause', this.onPauseBind);
this.player_.addEventListener('seeked', this.onSeekedBind);
this.player_.addEventListener('error', this.onErrorBind);
this.player_.addEventListener('abort', this.onAbortBind);
window.addEventListener('beforeunload', this.onWindowUnloadBind);
};
// Returns the session ID being currently analysed
HTML5PlayerAnalyticsConnector.prototype.getSessionId = function() {
return 'ANALYTICS-DEMO-' + this.rnd_;
};
// Function triggered when player starts to load new source
HTML5PlayerAnalyticsConnector.prototype.onLoadStart = function() {
this.onGeneric('HandShake', this.analytics_.handshake, function() {
var params = {
'assetId': 'YOUR_ASSET_ID',
'programId': 'YOUR_PROGRAM_ID'
};
this.analytics_.handshake(this.getSessionId(), params);
}.bind(this), false);
};
// Sends playback current time to the analytics engine
HTML5PlayerAnalyticsConnector.prototype.sendCurrentTime = function() {
var sessionId = this.getSessionId();
if (this.analytics_.getSessionState &&
this.analytics_.getSessionState(sessionId) === 'PLAYING') {
// This is important for the heartbeats to reflect accurate playback currentTime
this.analytics_.setCurrentTime(sessionId, this.player_.currentTime);
}
};
// Clears all timers bound to the analytics session
HTML5PlayerAnalyticsConnector.prototype.clearTimers = function() {
if(this.currentTimeTimer_) {
clearInterval(this.currentTimeTimer_);
}
this.currentTimeTimer_ = null;
};
// Registers a timer to send to the analytics engine regular currentTime updates
HTML5PlayerAnalyticsConnector.prototype.registerCurrentTimeTimer = function() {
this.clearTimers();
this.currentTimeTimer_ = setInterval(function() { this.sendCurrentTime(); }.bind(this), 1000);
};
// Function triggered when player is able to start playing media
HTML5PlayerAnalyticsConnector.prototype.onCanPlay = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('Created', this.analytics_.created, function() {
var params = {
'autoplay': true
};
this.analytics_.created(currentSessionId, params);
this.onStartPlay();
}.bind(this), false);
};
// Function triggered when player receives a command to start playing media
HTML5PlayerAnalyticsConnector.prototype.onStartPlay = function() {
this.onGeneric('Play', this.analytics_.play, function() {
var params = {
'techName' : 'NativeHTML5',
'version' : '1.0',
'techVersion': '1.0'
};
this.analytics_.play(this.getSessionId(), 0.0, params);
this.registerCurrentTimeTimer();
}.bind(this), false);
};
// Function triggered when the playback is paused
HTML5PlayerAnalyticsConnector.prototype.onPause = function() {
this.onGeneric('Pause', this.analytics_.paused, function() {
this.analytics_.paused(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
// Function triggered when player actually displays the first media elements on the screen
HTML5PlayerAnalyticsConnector.prototype.onPlaying = function() {
this.onGeneric('Playing', this.analytics_.playing, function() {
let params = {
'bitrate': 'YOUR_BITRATE',
'duration': this.player_.duration,
'mediaLocator': 'MEDIA_URL'
};
this.analytics_.playing(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
// Function triggered when the playback reaches the end of the stream
HTML5PlayerAnalyticsConnector.prototype.onEnded = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('End of Stream', this.analytics_.endOfStream, function() {
this.analytics_.endOfStream(currentSessionId);
}.bind(this), true, true);
};
// Function triggered when the media is seeked
HTML5PlayerAnalyticsConnector.prototype.onSeeked = function() {
this.onGeneric('Seeked', this.analytics_.seek, function() {
this.analytics_.seek(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
// Function triggered when an error occurs within the player's playback session
HTML5PlayerAnalyticsConnector.prototype.onError = function() {
this.onGeneric('Error', this.analytics_.error, function() {
const params = {
'code': 'YOUR_ERROR_CODE',
'errorMessage': 'YOUR_MESSAGE'
};
this.analytics_.error(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
// Function triggered when the playback session is interruped
HTML5PlayerAnalyticsConnector.prototype.onAbort = function() {
this.onGeneric('Dispose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId());
}.bind(this), true, true);
};
// Function triggered when the browser window is unloaded/closed
HTML5PlayerAnalyticsConnector.prototype.onWindowUnload = function() {
this.onGeneric('WindowClose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId(), this.player_.currentTime);
this.analytics_.dispatchNow(false);
}.bind(this), true);
};
HTML5PlayerAnalyticsConnector.prototype.onGeneric = function(eventName, eventFnc, callback) {
if (eventFnc && callback) {
callback();
}
else {
console.log('\'' + eventName + '\' was discarded.');
}
};
// Function used to unregister callbacks for player events and clear timers
HTML5PlayerAnalyticsConnector.prototype.dispose = function() {
this.clearTimers();
this.player_.removeEventListener('loadstart', this.onLoadStartBind);
this.player_.removeEventListener('canplay', this.onCanPlayBind);
this.player_.removeEventListener('playing', this.onPlayingBind);
this.player_.removeEventListener('ended', this.onEndedBind);
this.player_.removeEventListener('pause', this.onPauseBind);
this.player_.removeEventListener('seeked', this.onSeekedBind);
this.player_.removeEventListener('error', this.onErrorBind);
this.player_.removeEventListener('abort', this.onAbortBind);
window.removeEventListener('beforeunload', this.onWindowUnloadBind);
};
FAQs
This component collects playback events and sends them every 3s to EMP Exposure backend.
The npm package empanalytics-dev receives a total of 63 weekly downloads. As such, empanalytics-dev popularity was classified as not popular.
We found that empanalytics-dev demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.