/** * @file Dailymotion.js * Dailymotion Media Controller - Wrapper for HTML5 Media API */ //import videojs from 'video.js'; const Component = videojs.getComponent('Component'); const Tech = videojs.getComponent('Tech'); /** * Dailymotion Media Controller - Wrapper for HTML5 Media API * * @param {Object=} options Object of option names and values * @param {Function=} ready Ready callback function * @extends Tech * @class Dailymotion */ class Dailymotion extends Tech { constructor(options, ready) { super(options, ready); this.params = { id: this.options_.techId, autoplay: (this.player_.options_.autoplay) ? 1 : 0, chromeless: (this.player_.options_.dmControls) ? 0 : 1, html: 1, info: 1, logo: 1, controls: 'html', wmode: 'opaque', format: 'json', url: options.source.src }; // If we are not on a server, don't specify the origin (it will crash) if (window.location.protocol !== 'file:') { this.params.origin = window.location.protocol + '//' + window.location.hostname; } this.videoId = this.parseSrc(options.source.src); if (typeof this.videoId !== 'undefined') { this.setTimeout(() => { this.setPoster('//api.dailymotion.com/video/' + this.videoId + '?fields=poster_url&ads=false'); }, 100); } if (Dailymotion.isApiReady) { this.loadApi(); } else { // Add to the queue because the Dailymotion API is not ready Dailymotion.apiReadyQueue.push(this); } } createEl() { let el = videojs.createEl('iframe', { id: this.options_.techId, className: 'vjs-tech vjs-tech-dailymotion' }); let iframeContainer = videojs.createEl('iframe', { scrolling: 'no', marginWidth: 0, marginHeight: 0, frameBorder: 0, webkitAllowFullScreen: '', mozallowfullscreen: '', allowFullScreen: '', }); el.appendChild(iframeContainer); if (/MSIE (\d+\.\d+);/.test(navigator.userAgent) || !/(iPad|iPhone|iPod|Android)/g.test(navigator.userAgent)) { let divBlocker = videojs.createEl('div', { className: 'vjs-iframe-blocker', style: 'position:absolute;top:0;left:0;width:100%;height:100%' }); // In case the blocker is still there and we want to pause divBlocker.onclick = function () { this.pause(); }.bind(this); el.appendChild(divBlocker); } return el; } loadApi() { this.dmPlayer = new DM.player(this.options_.techId, { video: this.videoId, width: this.options_.width, height: this.options_.height, params: this.params }); this.setupTriggers(); this.dmPlayer.vjsTech = this; } parseSrc(src) { if (src) { // Regex that parse the video ID for any Dailymotion URL var regExp = /^.+dailymotion.com\/((video|hub)\/([^_]+))?[^#]*(#video=([^_&]+))?/; var match = src.match(regExp); return match ? match[5] || match[3] : null; } } setupTriggers() { this.dmPlayer.listeners = []; for (var i = Dailymotion.Events.length - 1; i >= 0; i--) { //videojs.on(this.dmPlayer, Dailymotion.Events[i], videojs.bind(this, this.eventHandler)); var listener = videojs.bind(this, this.eventHandler); this.dmPlayer.listeners.push({event: Dailymotion.Events[i], func: listener}); this.dmPlayer.addEventListener(Dailymotion.Events[i], listener); } } eventHandler(e) { this.onStateChange(e); this.trigger(e); } onStateChange(event) { let state = event.type; if (state !== this.lastState) { switch (state) { case -1: break; case 'apiready': this.triggerReady(); break; case 'video_end': this.trigger('ended'); break; case 'ad_play': this.trigger('play'); break; case 'video_start': case 'ad_start': this.trigger('playing'); this.trigger('play'); break; case 'play': break; case 'playing': break; case 'pause': break; case 'durationchange': break; case 'timeupdate': break; case 'progress': break; } this.lastState = state; } } poster() { return this.poster_; } setPoster(poster) { this.poster_ = poster; this.trigger('posterchange'); } /** * Set video * * @param {Object=} src Source object * @method setSrc */ src(src) { if (typeof src !== 'undefined') { this.src_ = this.parseSrc(src); this.dmPlayer.load(this.src_); } return this.src_; } currentSrc() { return this.src_; } play() { if (this.isReady_) { this.dmPlayer.play(); } else { if (!this.player_.options_.dmControls) { // Keep the big play button until it plays for real this.player_.bigPlayButton.show(); } } } ended() { if (this.isReady_) { var stateId = this.dmPlayer.getPlayerState(); return stateId === 0; } else { // We will play it when the API will be ready return false; } } pause() { this.dmPlayer.pause(!this.dmPlayer.paused); } paused() { return this.dmPlayer.paused; } currentTime() { return (this.dmPlayer && this.dmPlayer.currentTime) ? this.dmPlayer.currentTime : 0; } setCurrentTime(position) { this.dmPlayer.seek(position); } duration() { return (this.dmPlayer && this.dmPlayer.duration) ? this.dmPlayer.duration : 0; } volume() { if (isNaN(this.volume_)) { this.volume_ = this.dmPlayer.volume; } return this.volume_; } /** * Request to enter fullscreen * * @method enterFullScreen */ enterFullScreen() { this.dmPlayer.setFullscreen(true); } /** * Request to exit fullscreen * * @method exitFullScreen */ exitFullScreen() { this.dmPlayer.setFullscreen(false); } setVolume(percentAsDecimal) { if (typeof(percentAsDecimal) !== 'undefined' && percentAsDecimal !== this.volume_) { this.dmPlayer.setVolume(percentAsDecimal); this.volume_ = percentAsDecimal; this.player_.trigger('volumechange'); } } buffered() { return []; } controls() { return false; } muted() { return this.dmPlayer.muted; } setMuted(muted) { this.dmPlayer.setMuted(muted); this.setTimeout(function () { this.player_.trigger('volumechange'); }); } supportsFullScreen() { return true; } resetSrc_(callback) { callback(); } dispose() { this.resetSrc_(Function.prototype); super.dispose(this); } } Dailymotion.prototype.options_ = {}; Dailymotion.apiReadyQueue = []; Dailymotion.makeQueryString = function (args) { let querys = []; for (var key in args) { if (args.hasOwnProperty(key)) { querys.push(encodeURIComponent(key) + '=' + encodeURIComponent(args[key])); } } return querys.join('&'); }; const injectJs = function () { let tag = document.createElement('script'); tag.src = '//api.dmcdn.net/all.js'; let firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); } /* Dailymotion Support Testing -------------------------------------------------------- */ Dailymotion.isSupported = function () { return true; }; // Add Source Handler pattern functions to this tech Tech.withSourceHandlers(Dailymotion); /* * The default native source handler. * This simply passes the source to the video element. Nothing fancy. * * @param {Object} source The source object * @param {Flash} tech The instance of the Flash tech */ Dailymotion.nativeSourceHandler = {}; /** * Check if Flash can play the given videotype * @param {String} type The mimetype to check * @return {String} 'probably', 'maybe', or '' (empty string) */ Dailymotion.nativeSourceHandler.canPlayType = function (source) { const dashExtRE = /^video\/(dailymotion)/i; if (dashExtRE.test(source)) { return 'maybe'; } else { return ''; } }; /* * Check Flash can handle the source natively * * @param {Object} source The source object * @return {String} 'probably', 'maybe', or '' (empty string) */ Dailymotion.nativeSourceHandler.canHandleSource = function (source) { // If a type was provided we should rely on that if (source.type) { return Dailymotion.nativeSourceHandler.canPlayType(source.type); } else if (source.src) { return Dailymotion.nativeSourceHandler.canPlayType(source.src); } return ''; }; /* * Pass the source to the flash object * Adaptive source handlers will have more complicated workflows before passing * video data to the video element * * @param {Object} source The source object * @param {Flash} tech The instance of the Flash tech */ Dailymotion.nativeSourceHandler.handleSource = function (source, tech) { tech.src(source.src); }; /* * Clean up the source handler when disposing the player or switching sources.. * (no cleanup is needed when supporting the format natively) */ Dailymotion.nativeSourceHandler.dispose = function () { }; // Register the native source handler Dailymotion.registerSourceHandler(Dailymotion.nativeSourceHandler); /* * Set the tech's volume control support status * * @type {Boolean} */ Dailymotion.prototype['featuresVolumeControl'] = true; /* * Set the tech's playbackRate support status * * @type {Boolean} */ Dailymotion.prototype['featuresPlaybackRate'] = false; /* * Set the tech's status on moving the video element. * In iOS, if you move a video element in the DOM, it breaks video playback. * * @type {Boolean} */ Dailymotion.prototype['movingMediaElementInDOM'] = false; /* * Set the the tech's fullscreen resize support status. * HTML video is able to automatically resize when going to fullscreen. * (No longer appears to be used. Can probably be removed.) */ Dailymotion.prototype['featuresFullscreenResize'] = false; /* * Set the tech's timeupdate event support status * (this disables the manual timeupdate events of the Tech) */ Dailymotion.prototype['featuresTimeupdateEvents'] = false; /* * Set the tech's progress event support status * (this disables the manual progress events of the Tech) */ Dailymotion.prototype['featuresProgressEvents'] = false; /* * Sets the tech's status on native text track support * * @type {Boolean} */ Dailymotion.prototype['featuresNativeTextTracks'] = true; /* * Sets the tech's status on native audio track support * * @type {Boolean} */ Dailymotion.prototype['featuresNativeAudioTracks'] = true; /* * Sets the tech's status on native video track support * * @type {Boolean} */ Dailymotion.prototype['featuresNativeVideoTracks'] = false; Dailymotion.Events = 'apiready,ad_play,ad_start,ad_timeupdate,ad_pause,ad_end,video_start,video_end,play,playing,pause,ended,canplay,canplaythrough,timeupdate,progress,seeking,seeked,volumechange,durationchange,fullscreenchange,error'.split(','); videojs.options.Dailymotion = {}; Component.registerComponent('Dailymotion', Dailymotion); Tech.registerTech('Dailymotion', Dailymotion); injectJs(); // Called when Dailymotion API is ready to be used window.dmAsyncInit = function () { var dm; while ((dm = Dailymotion.apiReadyQueue.shift())) { dm.loadApi(); } Dailymotion.apiReadyQueue = []; Dailymotion.isApiReady = true; }; //export default Dailymotion;