UNPKG

mediaelement

Version:
486 lines (420 loc) 12.2 kB
'use strict'; /** * DailyMotion renderer * * Uses <iframe> approach and uses DailyMotion API to manipulate it. * @see https://developer.dailymotion.com/player * */ const DailyMotionApi = { /** * @type {Boolean} */ isSDKStarted: false, /** * @type {Boolean} */ isSDKLoaded: false, /** * @type {Array} */ iframeQueue: [], /** * Create a queue to prepare the creation of <iframe> * * @param {Object} settings - an object with settings needed to create <iframe> */ enqueueIframe: (settings) => { if (DailyMotionApi.isLoaded) { DailyMotionApi.createIframe(settings); } else { DailyMotionApi.loadIframeApi(); DailyMotionApi.iframeQueue.push(settings); } }, /** * Load DailyMotion API script on the header of the document * */ loadIframeApi: () => { if (!DailyMotionApi.isSDKStarted) { mejs.Utils.loadScript('https://api.dmcdn.net/all.js'); DailyMotionApi.isSDKStarted = true; } }, /** * Process queue of DailyMotion <iframe> element creation * */ apiReady: () => { DailyMotionApi.isLoaded = true; DailyMotionApi.isSDKLoaded = true; while (DailyMotionApi.iframeQueue.length > 0) { const settings = DailyMotionApi.iframeQueue.pop(); // Init SDK DM.init({ apiKey: settings.apiKey, status: settings.status, cookie: settings.cookie }); DailyMotionApi.createIframe(settings); } }, /** * Create a new instance of DailyMotion API player and trigger a custom event to initialize it * * @param {Object} settings - an object with settings needed to create <iframe> */ createIframe: (settings) => { const player = DM.player(settings.container, { height: settings.height || '100%', width: settings.width || '100%', video: settings.videoId, params: Object.assign({api: true}, settings.params), origin: location.host }); player.addEventListener('apiready', () => { window[`__ready__${settings.id}`](player, {paused: true, ended: false}); }); }, /** * Extract ID from DailyMotion's URL to be loaded through API * Valid URL format(s): * - http://www.dailymotion.com/embed/video/x35yawy * - http://dai.ly/x35yawy * * @param {String} url * @return {String} */ getDailyMotionId: (url) => { const parts = url.split('/'), lastPart = parts[parts.length - 1], dashParts = lastPart.split('_') ; return dashParts[0]; } }; const DailyMotionIframeRenderer = { name: 'dailymotion_iframe', options: { prefix: 'dailymotion_iframe', dailymotion: { width: '100%', height: '100%', params: { autoplay: false, chromeless: 1, info: 0, logo: 0, related: 0 }, apiKey: null, status: true, cookie: true } }, /** * Determine if a specific element type can be played with this render * * @param {String} type * @return {Boolean} */ canPlayType: (type) => ~['video/dailymotion', 'video/x-dailymotion'].indexOf(type.toLowerCase()), /** * Create the player instance and add all native events/methods/properties as possible * * @param {MediaElement} mediaElement Instance of mejs.MediaElement already created * @param {Object} options All the player configuration options passed through constructor * @param {Object[]} mediaFiles List of sources with format: {src: url, type: x/y-z} * @return {Object} */ create: (mediaElement, options, mediaFiles) => { const dm = {}, apiStack = [], readyState = 4 ; let events, dmPlayer = null, dmIframe = null, muted = mediaElement.originalNode.muted ; dm.options = options; dm.id = mediaElement.id + '_' + options.prefix; dm.mediaElement = mediaElement; // wrappers for get/set const props = mejs.html5media.properties, assignGettersSetters = (propName) => { // add to flash state that we will store const capName = `${propName.substring(0, 1).toUpperCase()}${propName.substring(1)}`; dm[`get${capName}`] = () => { if (dmPlayer !== null) { const value = null; // figure out how to get dm dta here switch (propName) { case 'currentTime': return dmPlayer.currentTime; case 'duration': return isNaN(dmPlayer.duration) ? 0 : dmPlayer.duration; case 'volume': return dmPlayer.volume; case 'paused': return dmPlayer.paused; case 'ended': return dmPlayer.ended; case 'muted': muted = dmPlayer.muted; return muted; case 'buffered': const percentLoaded = dmPlayer.bufferedTime, duration = dmPlayer.duration; return { start: () => { return 0; }, end: () => { return percentLoaded / duration; }, length: 1 }; case 'src': return mediaElement.originalNode.getAttribute('src'); case 'readyState': return readyState; } return value; } else { return null; } }; dm[`set${capName}`] = (value) => { if (dmPlayer !== null) { switch (propName) { case 'src': const url = typeof value === 'string' ? value : value[0].src; dmPlayer.load(DailyMotionApi.getDailyMotionId(url)); break; case 'currentTime': dmPlayer.seek(value); break; case 'muted': if (value === true) { dmPlayer.setVolume(0); } dmPlayer.setMuted(value); muted = value; setTimeout(() => { const event = mejs.Utils.createEvent('volumechange', dm); mediaElement.dispatchEvent(event); }, 50); break; case 'volume': dmPlayer.setVolume(value); if (value === 0 && !dmPlayer.muted) { dmPlayer.setMuted(true); muted = true; } else if (value > 0 && dmPlayer.muted) { dmPlayer.setMuted(false); muted = false; } setTimeout(() => { const event = mejs.Utils.createEvent('volumechange', dm); mediaElement.dispatchEvent(event); }, 50); break; case 'readyState': const event = mejs.Utils.createEvent('canplay', dm); mediaElement.dispatchEvent(event); break; default: console.log('dm ' + dm.id, propName, 'UNSUPPORTED property'); break; } } else { // store for after "READY" event fires apiStack.push({type: 'set', propName: propName, value: value}); } }; } ; for (let i = 0, total = props.length; i < total; i++) { assignGettersSetters(props[i]); } const methods = mejs.html5media.methods, assignMethods = (methodName) => { dm[methodName] = () => { if (dmPlayer !== null) { switch (methodName) { case 'play': return dmPlayer.play(); case 'pause': return dmPlayer.pause(); case 'load': return null; } } else { apiStack.push({type: 'call', methodName: methodName}); } }; } ; for (let i = 0, total = methods.length; i < total; i++) { assignMethods(methods[i]); } // Initial method to register all DailyMotion events when initializing <iframe> window['__ready__' + dm.id] = (_dmPlayer) => { mediaElement.dmPlayer = dmPlayer = _dmPlayer; if (apiStack.length) { for (let i = 0, total = apiStack.length; i < total; i++) { const stackItem = apiStack[i]; if (stackItem.type === 'set') { const propName = stackItem.propName, capName = `${propName.substring(0, 1).toUpperCase()}${propName.substring(1)}` ; dm[`set${capName}`](stackItem.value); } else if (stackItem.type === 'call') { dm[stackItem.methodName](); } } } dmIframe = document.getElementById(dm.id); events = ['mouseover', 'mouseout']; const assignEvents = (e) => { const event = mejs.Utils.createEvent(e.type, dm); mediaElement.dispatchEvent(event); }; for (let i = 0, total = events.length; i < total; i++) { dmIframe.addEventListener(events[i], assignEvents, false); } if (mediaElement.originalNode.muted) { dmPlayer.setVolume(0); dmPlayer.setMuted(true); } else { dmPlayer.setVolume(dmPlayer.volume); dmPlayer.setMuted(false); } events = mejs.html5media.events; events = events.concat(['click', 'mouseover', 'mouseout']); const assignNativeEvents = (eventName) => { // Deprecated event; not consider it if (eventName !== 'ended') { dmPlayer.addEventListener(eventName, (e) => { const event = mejs.Utils.createEvent(e.type, dm); mediaElement.dispatchEvent(event); }); } }; for (let i = 0, total = events.length; i < total; i++) { assignNativeEvents(events[i]); } // Custom DailyMotion events dmPlayer.addEventListener('ad_start', () => { let event = mejs.Utils.createEvent('play', dm); mediaElement.dispatchEvent(event); event = mejs.Utils.createEvent('progress', dm); mediaElement.dispatchEvent(event); event = mejs.Utils.createEvent('timeupdate', dm); mediaElement.dispatchEvent(event); }); dmPlayer.addEventListener('ad_timeupdate', () => { const event = mejs.Utils.createEvent('timeupdate', dm); mediaElement.dispatchEvent(event); }); dmPlayer.addEventListener('ad_pause', () => { const event = mejs.Utils.createEvent('pause', dm); mediaElement.dispatchEvent(event); }); dmPlayer.addEventListener('start', function () { if (dmPlayer.muted) { const event = mejs.Utils.createEvent('volumechange', dm); mediaElement.dispatchEvent(event); } }); dmPlayer.addEventListener('video_start', () => { const event = mejs.Utils.createEvent('play', dm); mediaElement.dispatchEvent(event); const playingEvent = mejs.Utils.createEvent('playing', dm); mediaElement.dispatchEvent(playingEvent); }); dmPlayer.addEventListener('ad_timeupdate', () => { const event = mejs.Utils.createEvent('timeupdate', dm); mediaElement.dispatchEvent(event); }); dmPlayer.addEventListener('video_end', () => { const event = mejs.Utils.createEvent('ended', dm); mediaElement.dispatchEvent(event); // Check `loop` attribute if (mediaElement.originalNode.getAttribute('loop')) { dmPlayer.play(); } }); // give initial events const initEvents = ['rendererready', 'loadedmetadata', 'loadeddata', 'canplay']; for (let i = 0, total = initEvents.length; i < total; i++) { const event = mejs.Utils.createEvent(initEvents[i], dm); mediaElement.dispatchEvent(event); } }; const dmContainer = document.createElement('div'); dmContainer.id = dm.id; mediaElement.appendChild(dmContainer); if (mediaElement.originalNode) { dmContainer.style.width = mediaElement.originalNode.style.width; dmContainer.style.height = mediaElement.originalNode.style.height; } mediaElement.originalNode.style.display = 'none'; const videoId = DailyMotionApi.getDailyMotionId(mediaFiles[0].src), dmSettings = { id: dm.id, container: dmContainer, videoId: videoId }; dmSettings.params = Object.assign({}, dm.options.dailymotion); // Check for `autoplay` and `muted` attributes to override settings dmSettings.params.controls = !!mediaElement.originalNode.controls; if (mediaElement.originalNode.autoplay) { dmSettings.params.autoplay = true; } if (mediaElement.originalNode.muted) { dmSettings.params.mute = true; } dmSettings.params.api = '1'; DailyMotionApi.enqueueIframe(dmSettings); dm.hide = () => { dm.pause(); if (dmIframe) { dmIframe.style.display = 'none'; } }; dm.show = () => { if (dmIframe) { dmIframe.style.display = ''; } }; dm.setSize = (width, height) => { if (dmIframe) { dmIframe.width = width; dmIframe.height = height; } }; dm.destroy = () => { dmPlayer.destroy(); }; return dm; } }; /* * Register DailyMotion event globally * */ mejs.Utils.typeChecks.push((url) => /\/\/((www\.)?dailymotion\.com|dai\.ly)/i.test(url) ? 'video/x-dailymotion' : null); window.dmAsyncInit = () => { DailyMotionApi.apiReady(); }; mejs.Renderers.add(DailyMotionIframeRenderer);