clappr-chromecast-plugin
Version:
Chromecast support for Clappr
1,490 lines (1,313 loc) • 74.6 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("clappr"));
else if(typeof define === 'function' && define.amd)
define(["clappr"], factory);
else if(typeof exports === 'object')
exports["ChromecastPlugin"] = factory(require("clappr"));
else
root["ChromecastPlugin"] = factory(root["Clappr"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _clappr = __webpack_require__(1);
var _chromecast_playback = __webpack_require__(2);
var _chromecast_playback2 = _interopRequireDefault(_chromecast_playback);
var _publicStyleScss = __webpack_require__(4);
var _publicStyleScss2 = _interopRequireDefault(_publicStyleScss);
var _lodashAssign = __webpack_require__(6);
var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
var _publicIc_cast_24dpSvg = __webpack_require__(17);
var _publicIc_cast_24dpSvg2 = _interopRequireDefault(_publicIc_cast_24dpSvg);
var _publicIc_cast0_24dpSvg = __webpack_require__(18);
var _publicIc_cast0_24dpSvg2 = _interopRequireDefault(_publicIc_cast0_24dpSvg);
var _publicIc_cast1_24dpSvg = __webpack_require__(19);
var _publicIc_cast1_24dpSvg2 = _interopRequireDefault(_publicIc_cast1_24dpSvg);
var _publicIc_cast2_24dpSvg = __webpack_require__(20);
var _publicIc_cast2_24dpSvg2 = _interopRequireDefault(_publicIc_cast2_24dpSvg);
var _publicIc_cast_connected_24dpSvg = __webpack_require__(21);
var _publicIc_cast_connected_24dpSvg2 = _interopRequireDefault(_publicIc_cast_connected_24dpSvg);
var DEVICE_STATE = {
'IDLE': 0,
'ACTIVE': 1,
'WARNING': 2,
'ERROR': 3
};
var DEFAULT_CLAPPR_APP_ID = '9DFB77C0';
var MIMETYPES = {
'mp4': 'video/mp4',
'ogg': 'video/ogg',
'3gpp': 'video/3gpp',
'webm': 'video/webm',
'mkv': 'video/x-matroska',
'm3u8': 'application/x-mpegurl',
'mpd': 'application/dash+xml'
};
MIMETYPES['ogv'] = MIMETYPES['ogg'];
MIMETYPES['3gp'] = MIMETYPES['3gpp'];
var ChromecastPlugin = (function (_UICorePlugin) {
_inherits(ChromecastPlugin, _UICorePlugin);
_createClass(ChromecastPlugin, [{
key: 'version',
get: function get() {
return ("0.1.1");
}
}, {
key: 'name',
get: function get() {
return 'chromecast';
}
}, {
key: 'tagName',
get: function get() {
return 'button';
}
}, {
key: 'attributes',
get: function get() {
return {
'class': 'chromecast-button',
'type': 'button'
};
}
}, {
key: 'events',
get: function get() {
return {
'click': 'click'
};
}
}, {
key: 'options',
get: function get() {
return this.core.options.chromecast || (this.core.options.chromecast = {});
}
}, {
key: 'container',
get: function get() {
return this.core.getCurrentContainer ? this.core.getCurrentContainer() : this.core.activeContainer; // Clappr 0.3.0 or greater
}
}, {
key: 'playback',
get: function get() {
return this.core.getCurrentPlayback ? this.core.getCurrentPlayback() : this.core.activePlayback; // Clappr 0.3.0 or greater
}
}], [{
key: 'Movie',
get: function get() {
return 'movie';
}
}, {
key: 'TvShow',
get: function get() {
return 'tv_show';
}
}, {
key: 'Generic',
get: function get() {
return 'none';
}
}, {
key: 'version',
get: function get() {
return ("0.1.1");
}
}]);
function ChromecastPlugin(core) {
_classCallCheck(this, ChromecastPlugin);
_get(Object.getPrototypeOf(ChromecastPlugin.prototype), 'constructor', this).call(this, core);
this.bootTryDelay = this.options.bootTryDelay || 500; // Default is 500 milliseconds between each attempt
this.bootMaxTryCount = this.options.bootMaxTryCount || 6; // Default is 6 attempts (3 seconds)
this.bootTryCount = 0;
if (this.isBootable()) {
this.appId = this.options.appId || DEFAULT_CLAPPR_APP_ID;
this.deviceState = DEVICE_STATE.IDLE;
this.embedScript();
} else {
this.disable();
}
}
_createClass(ChromecastPlugin, [{
key: 'bindEvents',
value: function bindEvents() {
this.listenTo(this.core.mediaControl, _clappr.Events.MEDIACONTROL_RENDERED, this.render);
if (_clappr.Events.CORE_ACTIVE_CONTAINER_CHANGED) {
// Clappr 0.3.0 or greater
this.listenTo(this.core, _clappr.Events.CORE_ACTIVE_CONTAINER_CHANGED, this.containerChanged);
} else {
this.listenTo(this.core.mediaControl, _clappr.Events.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged);
}
if (this.container) {
this.listenTo(this.container, _clappr.Events.CONTAINER_TIMEUPDATE, this.containerTimeUpdate);
this.listenTo(this.container, _clappr.Events.CONTAINER_PLAY, this.containerPlay);
this.listenTo(this.container, _clappr.Events.CONTAINER_ENDED, this.sessionStopped);
}
}
}, {
key: 'isBootable',
value: function isBootable() {
// Browser must be Chrome
if (!_clappr.Browser.isChrome) {
return false;
}
// Chrome lesser than or equals to 71
// does not require secure page
if (_clappr.Browser.version <= 71) {
return true;
}
// Chrome greater than or equals to 72
// require secure page
return this.isSecure();
}
}, {
key: 'isSecure',
value: function isSecure() {
return window.location.protocol === 'https:';
}
}, {
key: 'enable',
value: function enable() {
_get(Object.getPrototypeOf(ChromecastPlugin.prototype), 'enable', this).call(this);
this.render();
this.embedScript();
}
}, {
key: 'embedScript',
value: function embedScript() {
var _this = this;
if (!window.chrome || !window.chrome.cast || !window.chrome.cast.isAvailable) {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('async', 'async');
script.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js');
script.onload = function () {
return _this.bootstrapCastApi();
};
document.body.appendChild(script);
} else {
this.bootstrapCastApi();
}
}
}, {
key: 'bootstrapCastApi',
value: function bootstrapCastApi() {
var _this2 = this;
this.bootTryCount++;
if (this.bootTryCount > this.bootMaxTryCount) {
this.bootTryCount = 0;
_clappr.Log.warn('GCastApi bootstrap timeout');
this.disable();
return;
}
// The "chrome" property may not be available immediately on some iOS devices
if (window.chrome) {
this.bootTryCount = 0;
if (window.chrome.cast && window.chrome.cast.isAvailable) {
this.appId = this.appId || DEFAULT_CLAPPR_APP_ID;
this.initializeCastApi();
} else {
window['__onGCastApiAvailable'] = function (loaded, errorInfo) {
if (loaded) {
_this2.appId = _this2.appId || DEFAULT_CLAPPR_APP_ID;
_this2.initializeCastApi();
} else {
_clappr.Log.warn('GCastApi error', errorInfo);
_this2.disable();
}
};
}
} else {
setTimeout(function () {
_this2.bootstrapCastApi();
}, this.bootTryDelay);
}
}
}, {
key: 'initializeCastApi',
value: function initializeCastApi() {
var _this3 = this;
var autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;
var sessionRequest = new chrome.cast.SessionRequest(this.appId);
var apiConfig = new chrome.cast.ApiConfig(sessionRequest, function (session) {
return _this3.sessionListener(session);
}, function (e) {
return _this3.receiverListener(e);
}, autoJoinPolicy);
chrome.cast.initialize(apiConfig, function () {
return _clappr.Log.debug(_this3.name, 'init success');
}, function () {
return _clappr.Log.warn(_this3.name, 'init error');
});
}
}, {
key: 'sessionListener',
value: function sessionListener(session) {
_clappr.Log.debug(this.name, 'new session id:' + session.sessionId);
this.newSession(session);
}
}, {
key: 'sessionUpdateListener',
value: function sessionUpdateListener() {
if (this.session) {
_clappr.Log.debug(this.name, this.session.status);
if (this.session.status === chrome.cast.SessionStatus.STOPPED) {
this.sessionStopped();
this.session = null;
}
}
}
}, {
key: 'receiverListener',
value: function receiverListener(e) {
if (e === chrome.cast.ReceiverAvailability.AVAILABLE) {
_clappr.Log.debug(this.name, 'receiver found');
this.show();
} else {
_clappr.Log.debug(this.name, 'receiver list empty');
this.hide();
}
}
}, {
key: 'launchSuccess',
value: function launchSuccess(session) {
this.renderConnected();
clearInterval(this.connectAnimInterval);
this.core.mediaControl.resetKeepVisible();
_clappr.Log.debug(this.name, 'launch success - session: ' + session.sessionId);
this.newSession(session);
}
}, {
key: 'launchError',
value: function launchError(e) {
_clappr.Log.debug(this.name, 'error on launch', e);
this.renderDisconnected();
clearInterval(this.connectAnimInterval);
this.core.mediaControl.resetKeepVisible();
this.container.play();
}
}, {
key: 'loadMediaSuccess',
value: function loadMediaSuccess(how, mediaSession) {
_clappr.Log.debug(this.name, 'new media session', mediaSession, '(', how, ')');
this.originalPlayback = this.playback;
var options = (0, _lodashAssign2['default'])({}, this.originalPlayback.options, {
currentMedia: mediaSession,
mediaControl: this.core.mediaControl,
poster: this.options.poster || this.core.options.poster,
settings: this.originalPlayback.settings
});
this.src = this.originalPlayback.src;
this.playbackProxy = new _chromecast_playback2['default'](options);
this.playbackProxy.render();
this.core.$el.addClass('chromecast-active');
this.mediaSession = mediaSession;
this.originalPlayback.$el.remove();
var container = this.container;
container.$el.append(this.playbackProxy.$el);
container.stopListening();
container.playback = this.playbackProxy;
container.bindEvents();
container.settingsUpdate();
}
}, {
key: 'loadMediaError',
value: function loadMediaError(e) {
_clappr.Log.warn(this.name, 'media error', e);
}
}, {
key: 'newSession',
value: function newSession(session) {
var _this4 = this;
this.session = session;
this.deviceState = DEVICE_STATE.ACTIVE;
this.renderConnected();
session.addUpdateListener(function () {
return _this4.sessionUpdateListener();
});
this.containerPlay();
}
}, {
key: 'sessionStopped',
value: function sessionStopped() {
this.renderDisconnected();
var time = this.currentTime;
var playerState = undefined;
if (this.mediaSession) {
playerState = this.mediaSession.playerState;
this.mediaSession = null;
}
this.core.$el.removeClass('chromecast-active');
this.core.load(this.src || this.core.options.sources);
var container = this.container;
if (this.playbackProxy) {
if (this.playbackProxy.isPlaying() || playerState === 'PAUSED') {
container.once(_clappr.Events.CONTAINER_READY, function () {
container.play();
container.playback.seek(100 * time / container.getDuration());
});
}
this.playbackProxy.stop();
}
}
}, {
key: 'loadMedia',
value: function loadMedia() {
var _this5 = this;
this.container.pause();
var src = this.container.options.src;
_clappr.Log.debug(this.name, 'loading... ' + src);
var mediaInfo = this.createMediaInfo(src);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.autoplay = true;
if (this.currentTime) {
request.currentTime = this.currentTime;
}
this.session.loadMedia(request, function (mediaSession) {
return _this5.loadMediaSuccess('loadMedia', mediaSession);
}, function (e) {
return _this5.loadMediaError(e);
});
}
}, {
key: 'createMediaInfo',
value: function createMediaInfo(src) {
var mimeType = ChromecastPlugin.mimeTypeFor(src);
var mediaInfo = new chrome.cast.media.MediaInfo(src);
mediaInfo.contentType = this.options.contentType || mimeType;
mediaInfo.customData = this.options.customData;
var metadata = this.createMediaMetadata();
mediaInfo.metadata = metadata;
return mediaInfo;
}
}, {
key: 'createMediaMetadata',
value: function createMediaMetadata() {
this.options.media || (this.options.media = {});
var type = this.options.media.type;
var metadata = this.createCastMediaMetadata(type);
metadata.title = this.options.media.title;
metadata.subtitle = this.options.media.subtitle;
metadata.releaseDate = this.options.media.releaseDate;
if (type === ChromecastPlugin.TvShow) {
metadata.episode = this.options.media.episode;
metadata.originalAirdate = this.options.media.originalAirdate;
metadata.season = this.options.media.season;
metadata.seriesTitle = this.options.media.seriesTitle;
} else if (type === ChromecastPlugin.Movie) {
metadata.studio = this.options.media.studio;
}
if (this.options.media.images) {
metadata.images = this.options.media.images.map(function (url) {
return new chrome.cast.Image(url);
});
}
if (!metadata.images && this.options.poster) {
metadata.images = [new chrome.cast.Image(this.options.poster)];
}
if (!metadata.images && this.core.options.poster) {
metadata.images = [new chrome.cast.Image(this.core.options.poster)];
}
return metadata;
}
}, {
key: 'createCastMediaMetadata',
value: function createCastMediaMetadata(type) {
switch (type) {
case ChromecastPlugin.Movie:
return new chrome.cast.media.MovieMediaMetadata();
case ChromecastPlugin.TvShow:
return new chrome.cast.media.TvShowMediaMetadata();
default:
return new chrome.cast.media.GenericMediaMetadata();
}
}
}, {
key: 'show',
value: function show() {
this.$el.show();
}
}, {
key: 'hide',
value: function hide() {
this.$el.hide();
}
}, {
key: 'click',
value: function click() {
var _this6 = this;
this.currentTime = this.container.getCurrentTime();
this.container.pause();
chrome.cast.requestSession(function (session) {
return _this6.launchSuccess(session);
}, function (e) {
return _this6.launchError(e);
});
if (!this.session) {
(function () {
var position = 0;
var connectingIcons = [_publicIc_cast0_24dpSvg2['default'], _publicIc_cast1_24dpSvg2['default'], _publicIc_cast2_24dpSvg2['default']];
clearInterval(_this6.connectAnimInterval);
_this6.connectAnimInterval = setInterval(function () {
_this6.$el.html(connectingIcons[position]);
position = (position + 1) % 3;
}, 600);
_this6.core.mediaControl.setKeepVisible();
})();
}
}
}, {
key: 'containerChanged',
value: function containerChanged() {
this.stopListening();
this.bindEvents();
}
}, {
key: 'containerTimeUpdate',
value: function containerTimeUpdate(timeProgress) {
this.currentTime = timeProgress.current;
}
}, {
key: 'containerPlay',
value: function containerPlay() {
if (this.session && (!this.mediaSession || this.mediaSession.playerState === 'IDLE' || this.mediaSession.playerState === 'PAUSED')) {
_clappr.Log.debug(this.name, 'load media');
this.loadMedia();
}
}
}, {
key: 'renderConnected',
value: function renderConnected() {
this.$el.html(_publicIc_cast_connected_24dpSvg2['default']);
}
}, {
key: 'renderDisconnected',
value: function renderDisconnected() {
this.$el.html(_publicIc_cast_24dpSvg2['default']);
}
}, {
key: 'render',
value: function render() {
this.session ? this.renderConnected() : this.renderDisconnected();
this.core.mediaControl.$el.find('.media-control-right-panel[data-media-control]').append(this.$el);
this.$style && this.$style.remove();
this.$style = _clappr.Styler.getStyleFor(_publicStyleScss2['default'], { baseUrl: this.core.options.baseUrl });
this.core.$el.append(this.$style);
return this;
}
}], [{
key: 'mimeTypeFor',
value: function mimeTypeFor(srcUrl) {
var extension = (srcUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1];
if (MIMETYPES[extension]) {
return MIMETYPES[extension];
} else if (srcUrl.indexOf('.ism') > -1) {
return 'application/vnd.ms-sstr+xml';
}
}
}]);
return ChromecastPlugin;
})(_clappr.UICorePlugin);
exports['default'] = ChromecastPlugin;
module.exports = exports['default'];
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _clappr = __webpack_require__(1);
var _publicChromecastHtml = __webpack_require__(3);
var _publicChromecastHtml2 = _interopRequireDefault(_publicChromecastHtml);
var TICK_INTERVAL = 100;
var ChromecastPlayback = (function (_Playback) {
_inherits(ChromecastPlayback, _Playback);
_createClass(ChromecastPlayback, [{
key: 'name',
get: function get() {
return 'chromecast_playback';
}
}, {
key: 'template',
get: function get() {
return (0, _clappr.template)(_publicChromecastHtml2['default']);
}
}, {
key: 'attributes',
get: function get() {
return { 'class': 'chromecast-playback' };
}
}, {
key: 'isReady',
get: function get() {
return true;
}
}]);
function ChromecastPlayback(options) {
var _this = this;
_classCallCheck(this, ChromecastPlayback);
_get(Object.getPrototypeOf(ChromecastPlayback.prototype), 'constructor', this).call(this, options);
this.src = options.src;
this.currentMedia = options.currentMedia;
this.mediaControl = options.mediaControl;
this.currentMedia.addUpdateListener(function () {
return _this.onMediaStatusUpdate();
});
this.settings = options.settings;
var noVolume = function noVolume(name) {
return name != 'volume';
};
this.settings['default'] && (this.settings['default'] = this.settings['default'].filter(noVolume));
this.settings.left && (this.settings.left = this.settings.left.filter(noVolume));
this.settings.right && (this.settings.right = this.settings.right.filter(noVolume));
}
_createClass(ChromecastPlayback, [{
key: 'render',
value: function render() {
var template = this.template();
this.$el.html(template);
if (this.options.poster) {
this.$('.chromecast-playback-background').css('background-image', 'url(' + this.options.poster + ')');
} else {
this.$('.chromecast-playback-background').css('background-color', '#666');
}
}
}, {
key: 'play',
value: function play() {
this.currentMedia.play();
}
}, {
key: 'pause',
value: function pause() {
this.stopTimer();
this.currentMedia.pause();
if (this.getPlaybackType() === _clappr.Playback.LIVE) {
this.trigger(_clappr.Events.PLAYBACK_DVR, true);
}
}
}, {
key: 'stop',
value: function stop() {
this.stopTimer();
this.currentMedia.pause(); // FIXME: properly handle media stop
}
}, {
key: 'seek',
value: function seek(time) {
var _this2 = this;
this.stopTimer();
var request = new chrome.cast.media.SeekRequest();
request.currentTime = time;
this.currentMedia.seek(request, function () {
return _this2.startTimer();
}, function () {
return _clappr.Log.warn('seek failed');
});
if (this.getPlaybackType() === _clappr.Playback.LIVE) {
// assume live if time within 30 seconds of end of live stream
this.trigger(_clappr.Events.PLAYBACK_DVR, time < this.getDuration() - 30);
}
}
}, {
key: 'seekPercentage',
value: function seekPercentage(percentage) {
if (percentage >= 0 && percentage <= 100) {
var duration = this.getDuration();
this.seek(percentage * duration / 100);
}
}
}, {
key: 'startTimer',
value: function startTimer() {
var _this3 = this;
this.timer = setInterval(function () {
return _this3.updateMediaControl();
}, TICK_INTERVAL);
}
}, {
key: 'stopTimer',
value: function stopTimer() {
clearInterval(this.timer);
this.timer = null;
}
}, {
key: 'getDuration',
value: function getDuration() {
return this.currentMedia.media.duration;
}
}, {
key: 'isPlaying',
value: function isPlaying() {
return this.currentMedia.playerState === 'PLAYING' || this.currentMedia.playerState === 'BUFFERING';
}
}, {
key: 'getPlaybackType',
value: function getPlaybackType() {
return !!this.currentMedia.liveSeekableRange ? _clappr.Playback.LIVE : _clappr.Playback.VOD;
}
}, {
key: 'onMediaStatusUpdate',
value: function onMediaStatusUpdate() {
this.mediaControl.changeTogglePlay();
if (this.isPlaying() && !this.timer) {
this.startTimer();
}
if (this.currentMedia.playerState === 'BUFFERING') {
this.isBuffering = true;
this.trigger(_clappr.Events.PLAYBACK_BUFFERING, this.name);
} else if (this.currentMedia.playerState === 'PLAYING') {
if (this.isBuffering) {
this.isBuffering = false;
this.trigger(_clappr.Events.PLAYBACK_BUFFERFULL, this.name);
}
if (this.prevState !== this.currentMedia.playerState) {
this.trigger(_clappr.Events.PLAYBACK_PLAY, this.name);
}
} else if (this.currentMedia.playerState === 'IDLE') {
if (this.isBuffering) {
this.isBuffering = false;
this.trigger(_clappr.Events.PLAYBACK_BUFFERFULL, this.name);
}
this.trigger(_clappr.Events.PLAYBACK_ENDED, this.name);
} else if (this.currentMedia.playerState === 'PAUSED') {
if (this.prevState !== this.currentMedia.playerState) {
this.trigger(_clappr.Events.PLAYBACK_PAUSE, this.name);
}
}
this.prevState = this.currentMedia.playerState;
}
}, {
key: 'updateMediaControl',
value: function updateMediaControl() {
var position = this.currentMedia.getEstimatedTime();
var duration = this.currentMedia.media.duration;
this.trigger(_clappr.Events.PLAYBACK_TIMEUPDATE, { current: position, total: duration }, this.name);
}
}, {
key: 'show',
value: function show() {
this.$el.show();
}
}, {
key: 'hide',
value: function hide() {
this.$el.hide();
}
}]);
return ChromecastPlayback;
})(_clappr.Playback);
exports['default'] = ChromecastPlayback;
module.exports = exports['default'];
/***/ }),
/* 3 */
/***/ (function(module, exports) {
module.exports = "<div class=chromecast-playback-background></div><div class=chromecast-playback-overlay></div>";
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(5)();
// imports
// module
exports.push([module.id, ".chromecast-playback {\n height: 100%;\n width: 100%; }\n .chromecast-playback .chromecast-playback-background, .chromecast-playback .chromecast-playback-overlay {\n position: absolute;\n height: 100%;\n width: 100%; }\n .chromecast-playback .chromecast-playback-background {\n background-size: contain; }\n .chromecast-playback .chromecast-playback-overlay {\n background-color: #000;\n opacity: 0.4; }\n\n.chromecast-button {\n background: transparent;\n border: 0;\n width: 32px;\n height: 32px;\n font-size: 22px;\n line-height: 32px;\n letter-spacing: 0;\n margin: 0 6px;\n color: #fff;\n opacity: 0.5;\n vertical-align: middle;\n text-align: left;\n cursor: pointer;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n -webkit-transition: all 0.1s ease;\n -moz-transition: all 0.1s ease;\n -o-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .chromecast-button:hover {\n opacity: 0.75;\n text-shadow: rgba(255, 255, 255, 0.8) 0 0 5px; }\n .chromecast-button:focus {\n outline: none; }\n .chromecast-button svg {\n width: 24px;\n height: 24px; }\n .chromecast-button svg #cast, .chromecast-button svg #cast-on, .chromecast-button svg #Path {\n fill: #fff;\n stroke: #fff;\n stroke-width: 0.5px; }\n", ""]);
// exports
/***/ }),
/* 5 */
/***/ (function(module, exports) {
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
// css base code, injected by the css-loader
module.exports = function() {
var list = [];
// return the list of modules as css string
list.toString = function toString() {
var result = [];
for(var i = 0; i < this.length; i++) {
var item = this[i];
if(item[2]) {
result.push("@media " + item[2] + "{" + item[1] + "}");
} else {
result.push(item[1]);
}
}
return result.join("");
};
// import a list of modules into the list
list.i = function(modules, mediaQuery) {
if(typeof modules === "string")
modules = [[null, modules, ""]];
var alreadyImportedModules = {};
for(var i = 0; i < this.length; i++) {
var id = this[i][0];
if(typeof id === "number")
alreadyImportedModules[id] = true;
}
for(i = 0; i < modules.length; i++) {
var item = modules[i];
// skip already imported module
// this implementation is not 100% perfect for weird media query combinations
// when a module is imported multiple times with different media queries.
// I hope this will never occur (Hey this way we have smaller bundles)
if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
if(mediaQuery && !item[2]) {
item[2] = mediaQuery;
} else if(mediaQuery) {
item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
}
list.push(item);
}
}
};
return list;
};
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
/**
* lodash 3.2.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var baseAssign = __webpack_require__(7),
createAssigner = __webpack_require__(13),
keys = __webpack_require__(9);
/**
* A specialized version of `_.assign` for customizing assigned values without
* support for argument juggling, multiple sources, and `this` binding `customizer`
* functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {Function} customizer The function to customize assigned values.
* @returns {Object} Returns `object`.
*/
function assignWith(object, source, customizer) {
var index = -1,
props = keys(source),
length = props.length;
while (++index < length) {
var key = props[index],
value = object[key],
result = customizer(value, source[key], key, object, source);
if ((result === result ? (result !== value) : (value === value)) ||
(value === undefined && !(key in object))) {
object[key] = result;
}
}
return object;
}
/**
* Assigns own enumerable properties of source object(s) to the destination
* object. Subsequent sources overwrite property assignments of previous sources.
* If `customizer` is provided it is invoked to produce the assigned values.
* The `customizer` is bound to `thisArg` and invoked with five arguments:
* (objectValue, sourceValue, key, object, source).
*
* **Note:** This method mutates `object` and is based on
* [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
*
* @static
* @memberOf _
* @alias extend
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @param {Function} [customizer] The function to customize assigned values.
* @param {*} [thisArg] The `this` binding of `customizer`.
* @returns {Object} Returns `object`.
* @example
*
* _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
* // => { 'user': 'fred', 'age': 40 }
*
* // using a customizer callback
* var defaults = _.partialRight(_.assign, function(value, other) {
* return _.isUndefined(value) ? other : value;
* });
*
* defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
* // => { 'user': 'barney', 'age': 36 }
*/
var assign = createAssigner(function(object, source, customizer) {
return customizer
? assignWith(object, source, customizer)
: baseAssign(object, source);
});
module.exports = assign;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
/**
* lodash 3.2.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var baseCopy = __webpack_require__(8),
keys = __webpack_require__(9);
/**
* The base implementation of `_.assign` without support for argument juggling,
* multiple sources, and `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssign(object, source) {
return source == null
? object
: baseCopy(source, keys(source), object);
}
module.exports = baseAssign;
/***/ }),
/* 8 */
/***/ (function(module, exports) {
/**
* lodash 3.0.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* Copies properties of `source` to `object`.
*
* @private
* @param {Object} source The object to copy properties from.
* @param {Array} props The property names to copy.
* @param {Object} [object={}] The object to copy properties to.
* @returns {Object} Returns `object`.
*/
function baseCopy(source, props, object) {
object || (object = {});
var index = -1,
length = props.length;
while (++index < length) {
var key = props[index];
object[key] = source[key];
}
return object;
}
module.exports = baseCopy;
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
/**
* lodash 3.1.2 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var getNative = __webpack_require__(10),
isArguments = __webpack_require__(11),
isArray = __webpack_require__(12);
/** Used to detect unsigned integer values. */
var reIsUint = /^\d+$/;
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/* Native method references for those with the same name as other `lodash` methods. */
var nativeKeys = getNative(Object, 'keys');
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* Gets the "length" property value of `object`.
*
* **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
* that affects Safari on at least iOS 8.1-8.3 ARM64.
*
* @private
* @param {Object} object The object to query.
* @returns {*} Returns the "length" value.
*/
var getLength = baseProperty('length');
/**
* Checks if `value` is array-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
*/
function isArrayLike(value) {
return value != null && isLength(getLength(value));
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
length = length == null ? MAX_SAFE_INTEGER : length;
return value > -1 && value % 1 == 0 && value < length;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* A fallback implementation of `Object.keys` which creates an array of the
* own enumerable property names of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
*/
function shimKeys(object) {
var props = keysIn(object),
propsLength = props.length,
length = propsLength && object.length;
var allowIndexes = !!length && isLength(length) &&
(isArray(object) || isArguments(object));
var index = -1,
result = [];
while (++index < propsLength) {
var key = props[index];
if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
result.push(key);
}
}
return result;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Creates an array of the own enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects. See the
* [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
* for more details.
*
* @static
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keys(new Foo);
* // => ['a', 'b'] (iteration order is not guaranteed)
*
* _.keys('hi');
* // => ['0', '1']
*/
var keys = !nativeKeys ? shimKeys : function(object) {
var Ctor = object == null ? undefined : object.constructor;
if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
(typeof object != 'function' && isArrayLike(object))) {
return shimKeys(object);
}
return isObject(object) ? nativeKeys(object) : [];
};
/**
* Creates an array of the own and inherited enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keysIn(new Foo);
* // => ['a', 'b', 'c'] (iteration order is not guaranteed)
*/
function keysIn(object) {
if (object == null) {
return [];
}
if (!isObject(object)) {
object = Object(object);
}
var length = object.length;
length = (length && isLength(length) &&
(isArray(object) || isArguments(object)) && length) || 0;
var Ctor = object.constructor,
index = -1,
isProto = typeof Ctor == 'function' && Ctor.prototype === object,
result = Array(length),
skipIndexes = length > 0;
while (++index < length) {
result[index] = (index + '');
}
for (var key in object) {
if (!(skipIndexes && isIndex(key, length)) &&
!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
result.push(key);
}
}
return result;
}
module.exports = keys;
/***/ }),
/* 10 */
/***/ (function(module, exports) {
/**
* lodash 3.9.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var funcTag = '[object Function]';
/** Used to detect host constructors (Safari > 5). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var fnToString = Function.prototype.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = object == null ? undefined : object[key];
return isNative(value) ? value : undefined;
}
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 equivalents which return 'object' for typed array constructors.
return isObject(value) && objToString.call(value) == funcTag;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is a native function.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function, else `false`.
* @example
*
* _.isNative(Array.prototype.push);
* // => true
*
* _.isNative(_);
* // => false
*/
function isNative(value) {
if (value == null) {
return false;
}
if (isFunction(value)) {
return reIsNative.test(fnToString.call(value));
}
return isObjectLike(value) && reIsHostCtor.test(value);
}
module.exports = getNative;
/***/ }),
/* 11 */
/***/ (function(module, exports) {
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as references for various `Number` constants. */
var MAX_SAFE_INTEGER = 9007199254740991;
/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
funcTag = '[obj