From 2a3527ccb0788006ab71ae59e35f7051b6fe2716 Mon Sep 17 00:00:00 2001 From: Sara Arjona Date: Thu, 16 Sep 2021 18:16:09 +0200 Subject: [PATCH] MDL-72407 videojs: Remove videojs-flash and videojs-swf libraries Apart from removing these libraries because the Flash Player was deprecated in 2017 and officially discontinued on 31 December 2020, the rtmp and useflash settings have been removed too (they make no sense anymore). --- filter/mediaplugin/tests/filter_test.php | 2 - media/player/videojs/amd/build/loader.min.js | 2 +- .../videojs/amd/build/loader.min.js.map | 2 +- .../amd/build/videojs-flash-lazy.min.js | 2 - .../amd/build/videojs-flash-lazy.min.js.map | 1 - media/player/videojs/amd/src/loader.js | 7 +- .../videojs/amd/src/videojs-flash-lazy.js | 1455 ----------------- media/player/videojs/classes/plugin.php | 45 +- media/player/videojs/db/upgrade.php | 66 + media/player/videojs/lang/en/deprecated.txt | 4 + .../player/videojs/lang/en/media_videojs.php | 16 +- media/player/videojs/readme_moodle.txt | 11 - media/player/videojs/settings.php | 8 - media/player/videojs/tests/player_test.php | 80 +- media/player/videojs/thirdpartylibs.xml | 14 - media/player/videojs/version.php | 2 +- media/player/videojs/videojs/LICENSE | 13 - media/player/videojs/videojs/video-js.swf | Bin 17350 -> 0 bytes media/upgrade.txt | 5 + 19 files changed, 108 insertions(+), 1627 deletions(-) delete mode 100644 media/player/videojs/amd/build/videojs-flash-lazy.min.js delete mode 100644 media/player/videojs/amd/build/videojs-flash-lazy.min.js.map delete mode 100644 media/player/videojs/amd/src/videojs-flash-lazy.js create mode 100644 media/player/videojs/db/upgrade.php create mode 100644 media/player/videojs/lang/en/deprecated.txt delete mode 100644 media/player/videojs/videojs/LICENSE delete mode 100644 media/player/videojs/videojs/video-js.swf diff --git a/filter/mediaplugin/tests/filter_test.php b/filter/mediaplugin/tests/filter_test.php index de09814238f..c7e7cc57cd1 100644 --- a/filter/mediaplugin/tests/filter_test.php +++ b/filter/mediaplugin/tests/filter_test.php @@ -36,7 +36,6 @@ class filter_mediaplugin_testcase extends advanced_testcase { // We need to enable the media plugins. \core\plugininfo\media::set_enabled_plugins('vimeo,youtube,videojs,html5video,html5audio'); - set_config('useflash', true, 'media_videojs'); $filterplugin = new filter_mediaplugin(null, array()); @@ -59,7 +58,6 @@ class filter_mediaplugin_testcase extends advanced_testcase { 'test file', 'test file', 'test file', - 'test flv', 'test file', 'test ogg', 'test mp3', diff --git a/media/player/videojs/amd/build/loader.min.js b/media/player/videojs/amd/build/loader.min.js index 41f5a067ee6..76d1a45860b 100644 --- a/media/player/videojs/amd/build/loader.min.js +++ b/media/player/videojs/amd/build/loader.min.js @@ -1,2 +1,2 @@ -define ("media_videojs/loader",["exports","core/ajax","core/config","core_filters/events","core/localstorage","core/notification","jquery"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.setUp=void 0;b=h(b);c=h(c);e=h(e);f=h(f);g=h(g);var o="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function h(a){return a&&a.__esModule?a:{default:a}}function i(a,b){return n(a)||m(a,b)||k(a,b)||j()}function j(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function k(a,b){if(!a)return;if("string"==typeof a)return l(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return l(a,b)}function l(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);ca.length)b=a.length;for(var c=0,d=Array(b);c.\n\n/**\n * Video JS loader.\n *\n * This takes care of applying the filter on content which was dynamically loaded.\n *\n * @module media_videojs/loader\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Config from 'core/config';\nimport {eventTypes} from 'core_filters/events';\nimport LocalStorage from 'core/localstorage';\nimport Notification from 'core/notification';\nimport jQuery from 'jquery';\n\n/** @var {bool} Whether this is the first load of videojs module */\nlet firstLoad;\n\n/** @var {string} The language that is used in the player */\nlet language;\n\n/** @var {object} List of languages and translations for the current page */\nlet langStringCache;\n\n/**\n * Initialisei teh videojs Loader.\n *\n * Adds the listener for the event to then notify video.js.\n *\n * @method\n * @param {string} lang Language to be used in the player\n * @listens event:filterContentUpdated\n */\nexport const setUp = (lang) => {\n language = lang;\n firstLoad = true;\n\n // Notify Video.js about the nodes already present on the page.\n notifyVideoJS({\n detail: {\n nodes: document.body,\n }\n });\n\n // We need to call popover automatically if nodes are added to the page later.\n document.addEventListener(eventTypes.filterContentUpdated, notifyVideoJS);\n};\n\n/**\n * Notify video.js of new nodes.\n *\n * @param {Event} e The event.\n */\nconst notifyVideoJS = e => {\n const nodes = jQuery(e.detail.nodes);\n const selector = '.mediaplugin_videojs';\n const langStrings = getLanguageJson();\n\n // Find the descendants matching the expected parent of the audio and video\n // tags. Then also addBack the nodes matching the same selector. Finally,\n // we find the audio and video tags contained in those parents. Kind thanks\n // to jQuery for the simplicity.\n nodes.find(selector)\n .addBack(selector)\n .find('audio, video').each((index, element) => {\n const id = jQuery(element).attr('id');\n const config = jQuery(element).data('setup-lazy');\n const modulePromises = [import('media_videojs/video-lazy')];\n\n if (config.techOrder && config.techOrder.indexOf('youtube') !== -1) {\n // Add YouTube to the list of modules we require.\n modulePromises.push(import('media_videojs/Youtube-lazy'));\n }\n if (config.techOrder && config.techOrder.indexOf('flash') !== -1) {\n // Add Flash to the list of modules we require.\n modulePromises.push(import('media_videojs/videojs-flash-lazy'));\n }\n Promise.all([langStrings, ...modulePromises])\n .then(([langJson, videojs]) => {\n if (firstLoad) {\n videojs.options.flash.swf = `${Config.wwwroot}/media/player/videojs/videojs/video-js.swf`;\n videojs.options.playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n videojs.options.userActions = {\n hotkeys: true,\n };\n videojs.addLanguage(language, langJson);\n\n firstLoad = false;\n }\n videojs(id, config);\n return;\n })\n .catch(Notification.exception);\n });\n};\n\n/**\n * Returns the json object of the language strings to be used in the player.\n *\n * @returns {Promise}\n */\nconst getLanguageJson = () => {\n if (langStringCache) {\n return Promise.resolve(langStringCache);\n }\n\n const cacheKey = `media_videojs/${language}`;\n\n const rawCacheContent = LocalStorage.get(cacheKey);\n if (rawCacheContent) {\n const cacheContent = JSON.parse(rawCacheContent);\n\n langStringCache = cacheContent;\n\n return Promise.resolve(langStringCache);\n }\n\n const request = {\n methodname: 'media_videojs_get_language',\n args: {\n lang: language,\n },\n };\n\n return Ajax.call([request])[0]\n .then(langStringData => {\n LocalStorage.set(cacheKey, langStringData);\n\n return langStringData;\n })\n .then(result => JSON.parse(result))\n .then(langStrings => {\n langStringCache = langStrings;\n\n return langStrings;\n });\n};\n"],"file":"loader.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/loader.js"],"names":["firstLoad","language","langStringCache","setUp","lang","notifyVideoJS","detail","nodes","document","body","addEventListener","eventTypes","filterContentUpdated","e","selector","langStrings","getLanguageJson","find","addBack","each","index","element","id","attr","config","data","modulePromises","techOrder","indexOf","push","Promise","all","then","langJson","videojs","options","playbackRates","userActions","hotkeys","addLanguage","catch","Notification","exception","resolve","cacheKey","rawCacheContent","LocalStorage","get","cacheContent","JSON","parse","request","methodname","args","Ajax","call","langStringData","set","result"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Video JS loader.\n *\n * This takes care of applying the filter on content which was dynamically loaded.\n *\n * @module media_videojs/loader\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport {eventTypes} from 'core_filters/events';\nimport LocalStorage from 'core/localstorage';\nimport Notification from 'core/notification';\nimport jQuery from 'jquery';\n\n/** @var {bool} Whether this is the first load of videojs module */\nlet firstLoad;\n\n/** @var {string} The language that is used in the player */\nlet language;\n\n/** @var {object} List of languages and translations for the current page */\nlet langStringCache;\n\n/**\n * Initialisei teh videojs Loader.\n *\n * Adds the listener for the event to then notify video.js.\n *\n * @method\n * @param {string} lang Language to be used in the player\n * @listens event:filterContentUpdated\n */\nexport const setUp = (lang) => {\n language = lang;\n firstLoad = true;\n\n // Notify Video.js about the nodes already present on the page.\n notifyVideoJS({\n detail: {\n nodes: document.body,\n }\n });\n\n // We need to call popover automatically if nodes are added to the page later.\n document.addEventListener(eventTypes.filterContentUpdated, notifyVideoJS);\n};\n\n/**\n * Notify video.js of new nodes.\n *\n * @param {Event} e The event.\n */\nconst notifyVideoJS = e => {\n const nodes = jQuery(e.detail.nodes);\n const selector = '.mediaplugin_videojs';\n const langStrings = getLanguageJson();\n\n // Find the descendants matching the expected parent of the audio and video\n // tags. Then also addBack the nodes matching the same selector. Finally,\n // we find the audio and video tags contained in those parents. Kind thanks\n // to jQuery for the simplicity.\n nodes.find(selector)\n .addBack(selector)\n .find('audio, video').each((index, element) => {\n const id = jQuery(element).attr('id');\n const config = jQuery(element).data('setup-lazy');\n const modulePromises = [import('media_videojs/video-lazy')];\n\n if (config.techOrder && config.techOrder.indexOf('youtube') !== -1) {\n // Add YouTube to the list of modules we require.\n modulePromises.push(import('media_videojs/Youtube-lazy'));\n }\n\n Promise.all([langStrings, ...modulePromises])\n .then(([langJson, videojs]) => {\n if (firstLoad) {\n videojs.options.playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n videojs.options.userActions = {\n hotkeys: true,\n };\n videojs.addLanguage(language, langJson);\n\n firstLoad = false;\n }\n videojs(id, config);\n return;\n })\n .catch(Notification.exception);\n });\n};\n\n/**\n * Returns the json object of the language strings to be used in the player.\n *\n * @returns {Promise}\n */\nconst getLanguageJson = () => {\n if (langStringCache) {\n return Promise.resolve(langStringCache);\n }\n\n const cacheKey = `media_videojs/${language}`;\n\n const rawCacheContent = LocalStorage.get(cacheKey);\n if (rawCacheContent) {\n const cacheContent = JSON.parse(rawCacheContent);\n\n langStringCache = cacheContent;\n\n return Promise.resolve(langStringCache);\n }\n\n const request = {\n methodname: 'media_videojs_get_language',\n args: {\n lang: language,\n },\n };\n\n return Ajax.call([request])[0]\n .then(langStringData => {\n LocalStorage.set(cacheKey, langStringData);\n\n return langStringData;\n })\n .then(result => JSON.parse(result))\n .then(langStrings => {\n langStringCache = langStrings;\n\n return langStrings;\n });\n};\n"],"file":"loader.min.js"} \ No newline at end of file diff --git a/media/player/videojs/amd/build/videojs-flash-lazy.min.js b/media/player/videojs/amd/build/videojs-flash-lazy.min.js deleted file mode 100644 index 5a85b068f34..00000000000 --- a/media/player/videojs/amd/build/videojs-flash-lazy.min.js +++ /dev/null @@ -1,2 +0,0 @@ -function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}(function(a,b){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?module.exports=b(require("video.js")):"function"==typeof define&&define.amd?define ("media_videojs/videojs-flash-lazy",["media_videojs/video-lazy"],b):a.videojsFlash=b(a.videojs)})(this,function(a){'use strict';a=a&&a.hasOwnProperty("default")?a["default"]:a;var d="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},e;if("undefined"!=typeof window){e=window}else if("undefined"!=typeof d){e=d}else if("undefined"!=typeof self){e=self}else{e={}}var f=e,g=function(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}},h=function(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function, not "+_typeof(b))}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});if(b)Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b},j=function(a,b){if(!a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return b&&("object"===_typeof(b)||"function"==typeof b)?b:a},k=a.getComponent("Tech"),l=a.dom,m=a.url,n=a.createTimeRange,o=a.mergeOptions,p=f&&f.navigator||{},q=function(a){h(b,a);function b(c,d){g(this,b);var e=j(this,a.call(this,c,d));if(c.source){e.ready(function(){this.setSource(c.source)},!0)}if(c.startTime){e.ready(function(){this.load();this.play();this.currentTime(c.startTime)},!0)}f.videojs=f.videojs||{};f.videojs.Flash=f.videojs.Flash||{};f.videojs.Flash.onReady=b.onReady;f.videojs.Flash.onEvent=b.onEvent;f.videojs.Flash.onError=b.onError;e.on("seeked",function(){this.lastSeekTarget_=void 0});return e}b.prototype.createEl=function(){var a=this.options_;if(!a.swf){a.swf="https://vjs.zencdn.net/swf/5.4.2/video-js.swf"}var c=a.techId,d=o({readyFunction:"videojs.Flash.onReady",eventProxyFunction:"videojs.Flash.onEvent",errorEventProxyFunction:"videojs.Flash.onError",autoplay:a.autoplay,preload:a.preload,loop:a.loop,muted:a.muted},a.flashVars),e=o({wmode:"opaque",bgcolor:"#000000"},a.params),f=o({id:c,name:c,class:"vjs-tech"},a.attributes);this.el_=b.embed(a.swf,d,e,f);this.el_.tech=this;return this.el_};b.prototype.play=function(){if(this.ended()){this.setCurrentTime(0)}this.el_.vjs_play()};b.prototype.pause=function(){this.el_.vjs_pause()};b.prototype.src=function(a){if(a===void 0){return this.currentSrc()}return this.setSrc(a)};b.prototype.setSrc=function(a){var b=this;a=m.getAbsoluteURL(a);this.el_.vjs_src(a);if(this.autoplay()){this.setTimeout(function(){return b.play()},0)}};b.prototype.seeking=function(){return this.lastSeekTarget_!==void 0};b.prototype.setCurrentTime=function(b){var c=this.seekable();if(c.length){b=b>c.start(0)?b:c.start(0);b=b"});d=o({data:a,width:"100%",height:"100%"},d);Object.getOwnPropertyNames(d).forEach(function(a){g+=a+"=\""+d[a]+"\" "});return""+f+""};(function(a){a.streamingFormats={"rtmp/mp4":"MP4","rtmp/flv":"FLV"};a.streamFromParts=function(a,b){return a+"&"+b};a.streamToParts=function(a){var b={connection:"",stream:""};if(!a){return b}var c=a.search(/&(?![\w-]+=)/),d=void 0;if(-1!==c){d=c+1}else{c=d=a.lastIndexOf("/")+1;if(0===c){c=d=a.length}}b.connection=a.substring(0,c);b.stream=a.substring(d,a.length);return b};a.isStreamingType=function(b){return b in a.streamingFormats};a.RTMP_RE=/^rtmp[set]?:\/\//i;a.isStreamingSrc=function(b){return a.RTMP_RE.test(b)};a.rtmpSourceHandler={};a.rtmpSourceHandler.canPlayType=function(b){if(a.isStreamingType(b)){return"maybe"}return""};a.rtmpSourceHandler.canHandleSource=function(b){var c=a.rtmpSourceHandler.canPlayType(b.type);if(c){return c}if(a.isStreamingSrc(b.src)){return"maybe"}return""};a.rtmpSourceHandler.handleSource=function(b,c){var d=a.streamToParts(b.src);c.setRtmpConnection(d.connection);c.setRtmpStream(d.stream)};a.registerSourceHandler(a.rtmpSourceHandler);return a})(q);if(k.getTech("Flash")){a.log.warn("Not using videojs-flash as it appears to already be registered");a.log.warn("videojs-flash should only be used with video.js@6 and above")}else{a.registerTech("Flash",q)}q.VERSION="2.2.1";return q}); -//# sourceMappingURL=videojs-flash-lazy.min.js.map diff --git a/media/player/videojs/amd/build/videojs-flash-lazy.min.js.map b/media/player/videojs/amd/build/videojs-flash-lazy.min.js.map deleted file mode 100644 index afbf41cd11a..00000000000 --- a/media/player/videojs/amd/build/videojs-flash-lazy.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../src/videojs-flash-lazy.js"],"names":["global","factory","exports","module","require","define","amd","videojsFlash","videojs","hasOwnProperty","commonjsGlobal","globalThis","window","self","win","window_1","classCallCheck","instance","Constructor","TypeError","inherits","subClass","superClass","prototype","Object","create","constructor","value","enumerable","writable","configurable","setPrototypeOf","__proto__","possibleConstructorReturn","call","ReferenceError","Tech","getComponent","Dom","dom","Url","url","createTimeRange","mergeOptions","navigator","Flash","_Tech","options","ready","_this","source","setSource","startTime","load","play","currentTime","onReady","onEvent","onError","on","lastSeekTarget_","createEl","options_","swf","objId","techId","flashVars","readyFunction","eventProxyFunction","errorEventProxyFunction","autoplay","preload","loop","muted","params","wmode","bgcolor","attributes","id","name","el_","embed","tech","ended","setCurrentTime","vjs_play","pause","vjs_pause","src","_src","currentSrc","setSrc","_this2","getAbsoluteURL","vjs_src","setTimeout","seeking","time","seekable","length","start","end","trigger","vjs_setProperty","vjs_getProperty","currentSource_","duration","readyState","NaN","vjs_load","poster","setPoster","buffered","ranges","supportsFullScreen","enterFullScreen","getVideoPlaybackQuality","videoPlaybackQuality","performance","now","creationTime","timing","navigationStart","Date","_readWrite","_readOnly","_api","_createSetter","attr","attrUpper","charAt","toUpperCase","slice","val","_createGetter","i","_i","isSupported","browser","IS_CHROME","IS_ANDROID","IS_IOS","IS_SAFARI","IS_EDGE","version","withSourceHandlers","nativeSourceHandler","canPlayType","type","formats","canHandleSource","guessMimeType","ext","getFileExtension","replace","toLowerCase","handleSource","dispose","registerSourceHandler","currSwf","el","$","checkReady","triggerReady","swfID","eventName","args","Array","arguments","err","error","origin","version$$1","ActiveXObject","GetVariable","match","e","mimeTypes","enabledPlugin","plugins","description","split","code","getEmbedCode","obj","innerHTML","childNodes","flashVarsString","paramsString","attrsString","getOwnPropertyNames","forEach","key","movie","flashvars","allowScriptAccess","allowNetworking","data","width","height","streamingFormats","streamFromParts","connection","stream","streamToParts","parts","connEnd","search","streamBegin","lastIndexOf","substring","isStreamingType","srcType","RTMP_RE","isStreamingSrc","test","rtmpSourceHandler","can","srcParts","setRtmpConnection","setRtmpStream","getTech","log","warn","registerTech","VERSION"],"mappings":"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","sourcesContent":["/**\n * videojs-flash\n * @version 2.2.1\n * @copyright 2020 Brightcove, Inc.\n * @license Apache-2.0\n */\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :\n\ttypeof define === 'function' && define.amd ? define(['media_videojs/video-lazy'], factory) :\n\t(global.videojsFlash = factory(global.videojs));\n}(this, (function (videojs) { 'use strict';\n\nvideojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;\n\nvar version = \"5.4.2\";\n\nvar version$1 = \"2.2.1\";\n\n/**\n * @file flash-rtmp.js\n * @module flash-rtmp\n */\n\n/**\n * Add RTMP properties to the {@link Flash} Tech.\n *\n * @param {Flash} Flash\n * The flash tech class.\n *\n * @mixin FlashRtmpDecorator\n *\n * @return {Flash}\n * The flash tech with RTMP properties added.\n */\nfunction FlashRtmpDecorator(Flash) {\n Flash.streamingFormats = {\n 'rtmp/mp4': 'MP4',\n 'rtmp/flv': 'FLV'\n };\n\n /**\n * Join connection and stream with an ampersand.\n *\n * @param {string} connection\n * The connection string.\n *\n * @param {string} stream\n * The stream string.\n *\n * @return {string}\n * The connection and stream joined with an `&` character\n */\n Flash.streamFromParts = function (connection, stream) {\n return connection + '&' + stream;\n };\n\n /**\n * The flash parts object that contains connection and stream info.\n *\n * @typedef {Object} Flash~PartsObject\n *\n * @property {string} connection\n * The connection string of a source, defaults to an empty string.\n *\n * @property {string} stream\n * The stream string of the source, defaults to an empty string.\n */\n\n /**\n * Convert a source url into a stream and connection parts.\n *\n * @param {string} src\n * the source url\n *\n * @return {Flash~PartsObject}\n * The parts object that contains a connection and a stream\n */\n Flash.streamToParts = function (src) {\n var parts = {\n connection: '',\n stream: ''\n };\n\n if (!src) {\n return parts;\n }\n\n // Look for the normal URL separator we expect, '&'.\n // If found, we split the URL into two pieces around the\n // first '&'.\n var connEnd = src.search(/&(?![\\w-]+=)/);\n var streamBegin = void 0;\n\n if (connEnd !== -1) {\n streamBegin = connEnd + 1;\n } else {\n // If there's not a '&', we use the last '/' as the delimiter.\n connEnd = streamBegin = src.lastIndexOf('/') + 1;\n if (connEnd === 0) {\n // really, there's not a '/'?\n connEnd = streamBegin = src.length;\n }\n }\n\n parts.connection = src.substring(0, connEnd);\n parts.stream = src.substring(streamBegin, src.length);\n\n return parts;\n };\n\n /**\n * Check if the source type is a streaming type.\n *\n * @param {string} srcType\n * The mime type to check.\n *\n * @return {boolean}\n * - True if the source type is a streaming type.\n * - False if the source type is not a streaming type.\n */\n Flash.isStreamingType = function (srcType) {\n return srcType in Flash.streamingFormats;\n };\n\n // RTMP has four variations, any string starting\n // with one of these protocols should be valid\n\n /**\n * Regular expression used to check if the source is an rtmp source.\n *\n * @property {RegExp} Flash.RTMP_RE\n */\n Flash.RTMP_RE = /^rtmp[set]?:\\/\\//i;\n\n /**\n * Check if the source itself is a streaming type.\n *\n * @param {string} src\n * The url to the source.\n *\n * @return {boolean}\n * - True if the source url indicates that the source is streaming.\n * - False if the shource url indicates that the source url is not streaming.\n */\n Flash.isStreamingSrc = function (src) {\n return Flash.RTMP_RE.test(src);\n };\n\n /**\n * A source handler for RTMP urls\n * @type {Object}\n */\n Flash.rtmpSourceHandler = {};\n\n /**\n * Check if Flash can play the given mime type.\n *\n * @param {string} type\n * The mime type to check\n *\n * @return {string}\n * 'maybe', or '' (empty string)\n */\n Flash.rtmpSourceHandler.canPlayType = function (type) {\n if (Flash.isStreamingType(type)) {\n return 'maybe';\n }\n\n return '';\n };\n\n /**\n * Check if Flash can handle the source natively\n *\n * @param {Object} source\n * The source object\n *\n * @param {Object} [options]\n * The options passed to the tech\n *\n * @return {string}\n * 'maybe', or '' (empty string)\n */\n Flash.rtmpSourceHandler.canHandleSource = function (source, options) {\n var can = Flash.rtmpSourceHandler.canPlayType(source.type);\n\n if (can) {\n return can;\n }\n\n if (Flash.isStreamingSrc(source.src)) {\n return 'maybe';\n }\n\n return '';\n };\n\n /**\n * Pass the source to the flash object.\n *\n * @param {Object} source\n * The source object\n *\n * @param {Flash} tech\n * The instance of the Flash tech\n *\n * @param {Object} [options]\n * The options to pass to the source\n */\n Flash.rtmpSourceHandler.handleSource = function (source, tech, options) {\n var srcParts = Flash.streamToParts(source.src);\n\n tech.setRtmpConnection(srcParts.connection);\n tech.setRtmpStream(srcParts.stream);\n };\n\n // Register the native source handler\n Flash.registerSourceHandler(Flash.rtmpSourceHandler);\n\n return Flash;\n}\n\nvar commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\nvar win;\n\nif (typeof window !== \"undefined\") {\n win = window;\n} else if (typeof commonjsGlobal !== \"undefined\") {\n win = commonjsGlobal;\n} else if (typeof self !== \"undefined\"){\n win = self;\n} else {\n win = {};\n}\n\nvar window_1 = win;\n\nvar classCallCheck = function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n};\n\nvar inherits = function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n};\n\nvar possibleConstructorReturn = function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n};\n\n/**\n * @file flash.js\n * VideoJS-SWF - Custom Flash Player with HTML5-ish API\n * https://github.com/zencoder/video-js-swf\n * Not using setupTriggers. Using global onEvent func to distribute events\n */\n\nvar Tech = videojs.getComponent('Tech');\nvar Dom = videojs.dom;\nvar Url = videojs.url;\nvar createTimeRange = videojs.createTimeRange;\nvar mergeOptions = videojs.mergeOptions;\n\nvar navigator = window_1 && window_1.navigator || {};\n\n/**\n * Flash Media Controller - Wrapper for Flash Media API\n *\n * @mixes FlashRtmpDecorator\n * @mixes Tech~SouceHandlerAdditions\n * @extends Tech\n */\n\nvar Flash = function (_Tech) {\n inherits(Flash, _Tech);\n\n /**\n * Create an instance of this Tech.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Component~ReadyCallback} ready\n * Callback function to call when the `Flash` Tech is ready.\n */\n function Flash(options, ready) {\n classCallCheck(this, Flash);\n\n // Set the source when ready\n var _this = possibleConstructorReturn(this, _Tech.call(this, options, ready));\n\n if (options.source) {\n _this.ready(function () {\n this.setSource(options.source);\n }, true);\n }\n\n // Having issues with Flash reloading on certain page actions\n // (hide/resize/fullscreen) in certain browsers\n // This allows resetting the playhead when we catch the reload\n if (options.startTime) {\n _this.ready(function () {\n this.load();\n this.play();\n this.currentTime(options.startTime);\n }, true);\n }\n\n // Add global window functions that the swf expects\n // A 4.x workflow we weren't able to solve for in 5.0\n // because of the need to hard code these functions\n // into the swf for security reasons\n window_1.videojs = window_1.videojs || {};\n window_1.videojs.Flash = window_1.videojs.Flash || {};\n window_1.videojs.Flash.onReady = Flash.onReady;\n window_1.videojs.Flash.onEvent = Flash.onEvent;\n window_1.videojs.Flash.onError = Flash.onError;\n\n _this.on('seeked', function () {\n this.lastSeekTarget_ = undefined;\n });\n\n return _this;\n }\n\n /**\n * Create the `Flash` Tech's DOM element.\n *\n * @return {Element}\n * The element that gets created.\n */\n\n\n Flash.prototype.createEl = function createEl() {\n var options = this.options_;\n\n // If video.js is hosted locally you should also set the location\n // for the hosted swf, which should be relative to the page (not video.js)\n // Otherwise this adds a CDN url.\n // The CDN also auto-adds a swf URL for that specific version.\n if (!options.swf) {\n options.swf = 'https://vjs.zencdn.net/swf/' + version + '/video-js.swf';\n }\n\n // Generate ID for swf object\n var objId = options.techId;\n\n // Merge default flashvars with ones passed in to init\n var flashVars = mergeOptions({\n\n // SWF Callback Functions\n readyFunction: 'videojs.Flash.onReady',\n eventProxyFunction: 'videojs.Flash.onEvent',\n errorEventProxyFunction: 'videojs.Flash.onError',\n\n // Player Settings\n autoplay: options.autoplay,\n preload: options.preload,\n loop: options.loop,\n muted: options.muted\n\n }, options.flashVars);\n\n // Merge default parames with ones passed in\n var params = mergeOptions({\n // Opaque is needed to overlay controls, but can affect playback performance\n wmode: 'opaque',\n // Using bgcolor prevents a white flash when the object is loading\n bgcolor: '#000000'\n }, options.params);\n\n // Merge default attributes with ones passed in\n var attributes = mergeOptions({\n // Both ID and Name needed or swf to identify itself\n id: objId,\n name: objId,\n 'class': 'vjs-tech'\n }, options.attributes);\n\n this.el_ = Flash.embed(options.swf, flashVars, params, attributes);\n this.el_.tech = this;\n\n return this.el_;\n };\n\n /**\n * Called by {@link Player#play} to play using the `Flash` `Tech`.\n */\n\n\n Flash.prototype.play = function play() {\n if (this.ended()) {\n this.setCurrentTime(0);\n }\n this.el_.vjs_play();\n };\n\n /**\n * Called by {@link Player#pause} to pause using the `Flash` `Tech`.\n */\n\n\n Flash.prototype.pause = function pause() {\n this.el_.vjs_pause();\n };\n\n /**\n * A getter/setter for the `Flash` Tech's source object.\n * > Note: Please use {@link Flash#setSource}\n *\n * @param {Tech~SourceObject} [src]\n * The source object you want to set on the `Flash` techs.\n *\n * @return {Tech~SourceObject|undefined}\n * - The current source object when a source is not passed in.\n * - undefined when setting\n *\n * @deprecated Since version 5.\n */\n\n\n Flash.prototype.src = function src(_src) {\n if (_src === undefined) {\n return this.currentSrc();\n }\n\n // Setting src through `src` not `setSrc` will be deprecated\n return this.setSrc(_src);\n };\n\n /**\n * A getter/setter for the `Flash` Tech's source object.\n *\n * @param {Tech~SourceObject} [src]\n * The source object you want to set on the `Flash` techs.\n */\n\n\n Flash.prototype.setSrc = function setSrc(src) {\n var _this2 = this;\n\n // Make sure source URL is absolute.\n src = Url.getAbsoluteURL(src);\n this.el_.vjs_src(src);\n\n // Currently the SWF doesn't autoplay if you load a source later.\n // e.g. Load player w/ no source, wait 2s, set src.\n if (this.autoplay()) {\n this.setTimeout(function () {\n return _this2.play();\n }, 0);\n }\n };\n\n /**\n * Indicates whether the media is currently seeking to a new position or not.\n *\n * @return {boolean}\n * - True if seeking to a new position\n * - False otherwise\n */\n\n\n Flash.prototype.seeking = function seeking() {\n return this.lastSeekTarget_ !== undefined;\n };\n\n /**\n * Returns the current time in seconds that the media is at in playback.\n *\n * @param {number} time\n * Current playtime of the media in seconds.\n */\n\n\n Flash.prototype.setCurrentTime = function setCurrentTime(time) {\n var seekable = this.seekable();\n\n if (seekable.length) {\n // clamp to the current seekable range\n time = time > seekable.start(0) ? time : seekable.start(0);\n time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1);\n\n this.lastSeekTarget_ = time;\n this.trigger('seeking');\n this.el_.vjs_setProperty('currentTime', time);\n _Tech.prototype.setCurrentTime.call(this);\n }\n };\n\n /**\n * Get the current playback time in seconds\n *\n * @return {number}\n * The current time of playback in seconds.\n */\n\n\n Flash.prototype.currentTime = function currentTime() {\n // when seeking make the reported time keep up with the requested time\n // by reading the time we're seeking to\n if (this.seeking()) {\n return this.lastSeekTarget_ || 0;\n }\n return this.el_.vjs_getProperty('currentTime');\n };\n\n /**\n * Get the current source\n *\n * @method currentSrc\n * @return {Tech~SourceObject}\n * The current source\n */\n\n\n Flash.prototype.currentSrc = function currentSrc() {\n if (this.currentSource_) {\n return this.currentSource_.src;\n }\n return this.el_.vjs_getProperty('currentSrc');\n };\n\n /**\n * Get the total duration of the current media.\n *\n * @return {number}\n 8 The total duration of the current media.\n */\n\n\n Flash.prototype.duration = function duration() {\n if (this.readyState() === 0) {\n return NaN;\n }\n var duration = this.el_.vjs_getProperty('duration');\n\n return duration >= 0 ? duration : Infinity;\n };\n\n /**\n * Load media into Tech.\n */\n\n\n Flash.prototype.load = function load() {\n this.el_.vjs_load();\n };\n\n /**\n * Get the poster image that was set on the tech.\n */\n\n\n Flash.prototype.poster = function poster() {\n this.el_.vjs_getProperty('poster');\n };\n\n /**\n * Poster images are not handled by the Flash tech so make this is a no-op.\n */\n\n\n Flash.prototype.setPoster = function setPoster() {};\n\n /**\n * Determine the time ranges that can be seeked to in the media.\n *\n * @return {TimeRange}\n * Returns the time ranges that can be seeked to.\n */\n\n\n Flash.prototype.seekable = function seekable() {\n var duration = this.duration();\n\n if (duration === 0) {\n return createTimeRange();\n }\n return createTimeRange(0, duration);\n };\n\n /**\n * Get and create a `TimeRange` object for buffering.\n *\n * @return {TimeRange}\n * The time range object that was created.\n */\n\n\n Flash.prototype.buffered = function buffered() {\n var ranges = this.el_.vjs_getProperty('buffered');\n\n if (ranges.length === 0) {\n return createTimeRange();\n }\n return createTimeRange(ranges[0][0], ranges[0][1]);\n };\n\n /**\n * Get fullscreen support -\n *\n * Flash does not allow fullscreen through javascript\n * so this always returns false.\n *\n * @return {boolean}\n * The Flash tech does not support fullscreen, so it will always return false.\n */\n\n\n Flash.prototype.supportsFullScreen = function supportsFullScreen() {\n // Flash does not allow fullscreen through javascript\n return false;\n };\n\n /**\n * Flash does not allow fullscreen through javascript\n * so this always returns false.\n *\n * @return {boolean}\n * The Flash tech does not support fullscreen, so it will always return false.\n */\n\n\n Flash.prototype.enterFullScreen = function enterFullScreen() {\n return false;\n };\n\n /**\n * Gets available media playback quality metrics as specified by the W3C's Media\n * Playback Quality API.\n *\n * @see [Spec]{@link https://wicg.github.io/media-playback-quality}\n *\n * @return {Object}\n * An object with supported media playback quality metrics\n */\n\n\n Flash.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {\n var videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality');\n\n if (window_1.performance && typeof window_1.performance.now === 'function') {\n videoPlaybackQuality.creationTime = window_1.performance.now();\n } else if (window_1.performance && window_1.performance.timing && typeof window_1.performance.timing.navigationStart === 'number') {\n videoPlaybackQuality.creationTime = window_1.Date.now() - window_1.performance.timing.navigationStart;\n }\n\n return videoPlaybackQuality;\n };\n\n return Flash;\n}(Tech);\n\n// Create setters and getters for attributes\n\n\nvar _readWrite = ['rtmpConnection', 'rtmpStream', 'preload', 'defaultPlaybackRate', 'playbackRate', 'autoplay', 'loop', 'controls', 'volume', 'muted', 'defaultMuted'];\nvar _readOnly = ['networkState', 'readyState', 'initialTime', 'startOffsetTime', 'paused', 'ended', 'videoWidth', 'videoHeight'];\nvar _api = Flash.prototype;\n\n/**\n * Create setters for the swf on the element\n *\n * @param {string} attr\n * The name of the parameter\n *\n * @private\n */\nfunction _createSetter(attr) {\n var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);\n\n _api['set' + attrUpper] = function (val) {\n return this.el_.vjs_setProperty(attr, val);\n };\n}\n\n/**\n * Create getters for the swf on the element\n *\n * @param {string} attr\n * The name of the parameter\n *\n * @private\n */\nfunction _createGetter(attr) {\n _api[attr] = function () {\n return this.el_.vjs_getProperty(attr);\n };\n}\n\n// Create getter and setters for all read/write attributes\nfor (var i = 0; i < _readWrite.length; i++) {\n _createGetter(_readWrite[i]);\n _createSetter(_readWrite[i]);\n}\n\n// Create getters for read-only attributes\nfor (var _i = 0; _i < _readOnly.length; _i++) {\n _createGetter(_readOnly[_i]);\n}\n\n/** ------------------------------ Getters ------------------------------ **/\n/**\n * Get the value of `rtmpConnection` from the swf.\n *\n * @method Flash#rtmpConnection\n * @return {string}\n * The current value of `rtmpConnection` on the swf.\n */\n\n/**\n * Get the value of `rtmpStream` from the swf.\n *\n * @method Flash#rtmpStream\n * @return {string}\n * The current value of `rtmpStream` on the swf.\n */\n\n/**\n * Get the value of `preload` from the swf. `preload` indicates\n * what should download before the media is interacted with. It can have the following\n * values:\n * - none: nothing should be downloaded\n * - metadata: poster and the first few frames of the media may be downloaded to get\n * media dimensions and other metadata\n * - auto: allow the media and metadata for the media to be downloaded before\n * interaction\n *\n * @method Flash#preload\n * @return {string}\n * The value of `preload` from the swf. Will be 'none', 'metadata',\n * or 'auto'.\n */\n\n/**\n * Get the value of `defaultPlaybackRate` from the swf.\n *\n * @method Flash#defaultPlaybackRate\n * @return {number}\n * The current value of `defaultPlaybackRate` on the swf.\n */\n\n/**\n * Get the value of `playbackRate` from the swf. `playbackRate` indicates\n * the rate at which the media is currently playing back. Examples:\n * - if playbackRate is set to 2, media will play twice as fast.\n * - if playbackRate is set to 0.5, media will play half as fast.\n *\n * @method Flash#playbackRate\n * @return {number}\n * The value of `playbackRate` from the swf. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n */\n\n/**\n * Get the value of `autoplay` from the swf. `autoplay` indicates\n * that the media should start to play as soon as the page is ready.\n *\n * @method Flash#autoplay\n * @return {boolean}\n * - The value of `autoplay` from the swf.\n * - True indicates that the media ashould start as soon as the page loads.\n * - False indicates that the media should not start as soon as the page loads.\n */\n\n/**\n * Get the value of `loop` from the swf. `loop` indicates\n * that the media should return to the start of the media and continue playing once\n * it reaches the end.\n *\n * @method Flash#loop\n * @return {boolean}\n * - The value of `loop` from the swf.\n * - True indicates that playback should seek back to start once\n * the end of a media is reached.\n * - False indicates that playback should not loop back to the start when the\n * end of the media is reached.\n */\n\n/**\n * Get the value of `mediaGroup` from the swf.\n *\n * @method Flash#mediaGroup\n * @return {string}\n * The current value of `mediaGroup` on the swf.\n */\n\n/**\n * Get the value of `controller` from the swf.\n *\n * @method Flash#controller\n * @return {string}\n * The current value of `controller` on the swf.\n */\n\n/**\n * Get the value of `controls` from the swf. `controls` indicates\n * whether the native flash controls should be shown or hidden.\n *\n * @method Flash#controls\n * @return {boolean}\n * - The value of `controls` from the swf.\n * - True indicates that native controls should be showing.\n * - False indicates that native controls should be hidden.\n */\n\n/**\n * Get the value of the `volume` from the swf. `volume` indicates the current\n * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and\n * so on.\n *\n * @method Flash#volume\n * @return {number}\n * The volume percent as a decimal. Value will be between 0-1.\n */\n\n/**\n * Get the value of the `muted` from the swf. `muted` indicates the current\n * audio level should be silent.\n *\n * @method Flash#muted\n * @return {boolean}\n * - True if the audio should be set to silent\n * - False otherwise\n */\n\n/**\n * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates\n * whether the media should start muted or not. Only changes the default state of the\n * media. `muted` and `defaultMuted` can have different values. `muted` indicates the\n * current state.\n *\n * @method Flash#defaultMuted\n * @return {boolean}\n * - The value of `defaultMuted` from the swf.\n * - True indicates that the media should start muted.\n * - False indicates that the media should not start muted.\n */\n\n/**\n * Get the value of `networkState` from the swf. `networkState` indicates\n * the current network state. It returns an enumeration from the following list:\n * - 0: NETWORK_EMPTY\n * - 1: NEWORK_IDLE\n * - 2: NETWORK_LOADING\n * - 3: NETWORK_NO_SOURCE\n *\n * @method Flash#networkState\n * @return {number}\n * The value of `networkState` from the swf. This will be a number\n * from the list in the description.\n */\n\n/**\n * Get the value of `readyState` from the swf. `readyState` indicates\n * the current state of the media element. It returns an enumeration from the\n * following list:\n * - 0: HAVE_NOTHING\n * - 1: HAVE_METADATA\n * - 2: HAVE_CURRENT_DATA\n * - 3: HAVE_FUTURE_DATA\n * - 4: HAVE_ENOUGH_DATA\n *\n * @method Flash#readyState\n * @return {number}\n * The value of `readyState` from the swf. This will be a number\n * from the list in the description.\n */\n\n/**\n * Get the value of `readyState` from the swf. `readyState` indicates\n * the current state of the media element. It returns an enumeration from the\n * following list:\n * - 0: HAVE_NOTHING\n * - 1: HAVE_METADATA\n * - 2: HAVE_CURRENT_DATA\n * - 3: HAVE_FUTURE_DATA\n * - 4: HAVE_ENOUGH_DATA\n *\n * @method Flash#readyState\n * @return {number}\n * The value of `readyState` from the swf. This will be a number\n * from the list in the description.\n */\n\n/**\n * Get the value of `initialTime` from the swf.\n *\n * @method Flash#initialTime\n * @return {number}\n * The `initialTime` proprety on the swf.\n */\n\n/**\n * Get the value of `startOffsetTime` from the swf.\n *\n * @method Flash#startOffsetTime\n * @return {number}\n * The `startOffsetTime` proprety on the swf.\n */\n\n/**\n * Get the value of `paused` from the swf. `paused` indicates whether the swf\n * is current paused or not.\n *\n * @method Flash#paused\n * @return {boolean}\n * The value of `paused` from the swf.\n */\n\n/**\n * Get the value of `ended` from the swf. `ended` indicates whether\n * the media has reached the end or not.\n *\n * @method Flash#ended\n * @return {boolean}\n * - True indicates that the media has ended.\n * - False indicates that the media has not ended.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}\n */\n\n/**\n * Get the value of `videoWidth` from the swf. `videoWidth` indicates\n * the current width of the media in css pixels.\n *\n * @method Flash#videoWidth\n * @return {number}\n * The value of `videoWidth` from the swf. This will be a number\n * in css pixels.\n */\n\n/**\n * Get the value of `videoHeight` from the swf. `videoHeigth` indicates\n * the current height of the media in css pixels.\n *\n * @method Flassh.prototype.videoHeight\n * @return {number}\n * The value of `videoHeight` from the swf. This will be a number\n * in css pixels.\n */\n/** ------------------------------ Setters ------------------------------ **/\n\n/**\n * Set the value of `rtmpConnection` on the swf.\n *\n * @method Flash#setRtmpConnection\n * @param {string} rtmpConnection\n * New value to set the `rtmpConnection` property to.\n */\n\n/**\n * Set the value of `rtmpStream` on the swf.\n *\n * @method Flash#setRtmpStream\n * @param {string} rtmpStream\n * New value to set the `rtmpStream` property to.\n */\n\n/**\n * Set the value of `preload` on the swf. `preload` indicates\n * what should download before the media is interacted with. It can have the following\n * values:\n * - none: nothing should be downloaded\n * - metadata: poster and the first few frames of the media may be downloaded to get\n * media dimensions and other metadata\n * - auto: allow the media and metadata for the media to be downloaded before\n * interaction\n *\n * @method Flash#setPreload\n * @param {string} preload\n * The value of `preload` to set on the swf. Should be 'none', 'metadata',\n * or 'auto'.\n */\n\n/**\n * Set the value of `defaultPlaybackRate` on the swf.\n *\n * @method Flash#setDefaultPlaybackRate\n * @param {number} defaultPlaybackRate\n * New value to set the `defaultPlaybackRate` property to.\n */\n\n/**\n * Set the value of `playbackRate` on the swf. `playbackRate` indicates\n * the rate at which the media is currently playing back. Examples:\n * - if playbackRate is set to 2, media will play twice as fast.\n * - if playbackRate is set to 0.5, media will play half as fast.\n *\n * @method Flash#setPlaybackRate\n * @param {number} playbackRate\n * New value of `playbackRate` on the swf. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n */\n\n/**\n * Set the value of `autoplay` on the swf. `autoplay` indicates\n * that the media should start to play as soon as the page is ready.\n *\n * @method Flash#setAutoplay\n * @param {boolean} autoplay\n * - The value of `autoplay` from the swf.\n * - True indicates that the media ashould start as soon as the page loads.\n * - False indicates that the media should not start as soon as the page loads.\n */\n\n/**\n * Set the value of `loop` on the swf. `loop` indicates\n * that the media should return to the start of the media and continue playing once\n * it reaches the end.\n *\n * @method Flash#setLoop\n * @param {boolean} loop\n * - True indicates that playback should seek back to start once\n * the end of a media is reached.\n * - False indicates that playback should not loop back to the start when the\n * end of the media is reached.\n */\n\n/**\n * Set the value of `mediaGroup` on the swf.\n *\n * @method Flash#setMediaGroup\n * @param {string} mediaGroup\n * New value of `mediaGroup` to set on the swf.\n */\n\n/**\n * Set the value of `controller` on the swf.\n *\n * @method Flash#setController\n * @param {string} controller\n * New value the current value of `controller` on the swf.\n */\n\n/**\n * Get the value of `controls` from the swf. `controls` indicates\n * whether the native flash controls should be shown or hidden.\n *\n * @method Flash#controls\n * @return {boolean}\n * - The value of `controls` from the swf.\n * - True indicates that native controls should be showing.\n * - False indicates that native controls should be hidden.\n */\n\n/**\n * Set the value of the `volume` on the swf. `volume` indicates the current\n * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and\n * so on.\n *\n * @method Flash#setVolume\n * @param {number} percentAsDecimal\n * The volume percent as a decimal. Value will be between 0-1.\n */\n\n/**\n * Set the value of the `muted` on the swf. `muted` indicates that the current\n * audio level should be silent.\n *\n * @method Flash#setMuted\n * @param {boolean} muted\n * - True if the audio should be set to silent\n * - False otherwise\n */\n\n/**\n * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates\n * whether the media should start muted or not. Only changes the default state of the\n * media. `muted` and `defaultMuted` can have different values. `muted` indicates the\n * current state.\n *\n * @method Flash#setDefaultMuted\n * @param {boolean} defaultMuted\n * - True indicates that the media should start muted.\n * - False indicates that the media should not start muted.\n */\n\n/* Flash Support Testing -------------------------------------------------------- */\n\n/**\n * Check if the Flash tech is currently supported.\n *\n * @return {boolean}\n * - True for Chrome and Safari Desktop and Microsoft Edge and if flash tech is supported\n * - False otherwise\n */\nFlash.isSupported = function () {\n // for Chrome Desktop and Safari Desktop\n if (videojs.browser.IS_CHROME && (!videojs.browser.IS_ANDROID || !videojs.browser.IS_IOS) || videojs.browser.IS_SAFARI && !videojs.browser.IS_IOS || videojs.browser.IS_EDGE) {\n return true;\n }\n // for other browsers\n return Flash.version()[0] >= 10;\n};\n\n// Add Source Handler pattern functions to this tech\nTech.withSourceHandlers(Flash);\n\n/*\n * Native source handler for flash, simply passes the source to the swf element.\n *\n * @property {Tech~SourceObject} source\n * The source object\n *\n * @property {Flash} tech\n * The instance of the Flash tech\n */\nFlash.nativeSourceHandler = {};\n\n/**\n * Check if the Flash can play the given mime type.\n *\n * @param {string} type\n * The mimetype to check\n *\n * @return {string}\n * 'maybe', or '' (empty string)\n */\nFlash.nativeSourceHandler.canPlayType = function (type) {\n if (type in Flash.formats) {\n return 'maybe';\n }\n\n return '';\n};\n\n/**\n * Check if the media element can handle a source natively.\n *\n * @param {Tech~SourceObject} source\n * The source object\n *\n * @param {Object} [options]\n * Options to be passed to the tech.\n *\n * @return {string}\n * 'maybe', or '' (empty string).\n */\nFlash.nativeSourceHandler.canHandleSource = function (source, options) {\n var type = void 0;\n\n /**\n * Guess the mime type of a file if it does not have one\n *\n * @param {Tech~SourceObject} src\n * The source object to guess the mime type for\n *\n * @return {string}\n * The mime type that was guessed\n */\n function guessMimeType(src) {\n var ext = Url.getFileExtension(src);\n\n if (ext) {\n return 'video/' + ext;\n }\n return '';\n }\n\n if (!source.type) {\n type = guessMimeType(source.src);\n } else {\n // Strip code information from the type because we don't get that specific\n type = source.type.replace(/;.*/, '').toLowerCase();\n }\n\n return Flash.nativeSourceHandler.canPlayType(type);\n};\n\n/**\n * Pass the source to the swf.\n *\n * @param {Tech~SourceObject} source\n * The source object\n *\n * @param {Flash} tech\n * The instance of the Flash tech\n *\n * @param {Object} [options]\n * The options to pass to the source\n */\nFlash.nativeSourceHandler.handleSource = function (source, tech, options) {\n tech.setSrc(source.src);\n};\n\n/**\n * noop for native source handler dispose, as cleanup will happen automatically.\n */\nFlash.nativeSourceHandler.dispose = function () {};\n\n// Register the native source handler\nFlash.registerSourceHandler(Flash.nativeSourceHandler);\n\n/**\n * Flash supported mime types.\n *\n * @constant {Object}\n */\nFlash.formats = {\n 'video/flv': 'FLV',\n 'video/x-flv': 'FLV',\n 'video/mp4': 'MP4',\n 'video/m4v': 'MP4'\n};\n\n/**\n * Called when the the swf is \"ready\", and makes sure that the swf is really\n * ready using {@link Flash#checkReady}\n *\n * @param {Object} currSwf\n * The current swf object\n */\nFlash.onReady = function (currSwf) {\n var el = Dom.$('#' + currSwf);\n var tech = el && el.tech;\n\n // if there is no el then the tech has been disposed\n // and the tech element was removed from the player div\n if (tech && tech.el()) {\n // check that the flash object is really ready\n Flash.checkReady(tech);\n }\n};\n\n/**\n * The SWF isn't always ready when it says it is. Sometimes the API functions still\n * need to be added to the object. If it's not ready, we set a timeout to check again\n * shortly.\n *\n * @param {Flash} tech\n * The instance of the flash tech to check.\n */\nFlash.checkReady = function (tech) {\n // stop worrying if the tech has been disposed\n if (!tech.el()) {\n return;\n }\n\n // check if API property exists\n if (tech.el().vjs_getProperty) {\n // tell tech it's ready\n tech.triggerReady();\n } else {\n // wait longer\n this.setTimeout(function () {\n Flash.checkReady(tech);\n }, 50);\n }\n};\n\n/**\n * Trigger events from the swf on the Flash Tech.\n *\n * @param {number} swfID\n * The id of the swf that had the event\n *\n * @param {string} eventName\n * The name of the event to trigger\n */\nFlash.onEvent = function (swfID, eventName) {\n var tech = Dom.$('#' + swfID).tech;\n var args = Array.prototype.slice.call(arguments, 2);\n\n // dispatch Flash events asynchronously for two reasons:\n // - Flash swallows any exceptions generated by javascript it\n // invokes\n // - Flash is suspended until the javascript returns which may cause\n // playback performance issues\n tech.setTimeout(function () {\n tech.trigger(eventName, args);\n }, 1);\n};\n\n/**\n * Log errors from the swf on the Flash tech.\n *\n * @param {number} swfID\n * The id of the swf that had an error.\n *\n * @param {string} err\n * The error to set on the Flash Tech.\n *\n * @return {MediaError|undefined}\n * - Returns a MediaError when err is 'srcnotfound'\n * - Returns undefined otherwise.\n */\nFlash.onError = function (swfID, err) {\n var tech = Dom.$('#' + swfID).tech;\n\n // trigger MEDIA_ERR_SRC_NOT_SUPPORTED\n if (err === 'srcnotfound') {\n return tech.error(4);\n }\n\n // trigger a custom error\n if (typeof err === 'string') {\n tech.error('FLASH: ' + err);\n } else {\n err.origin = 'flash';\n tech.error(err);\n }\n};\n\n/**\n * Get the current version of Flash that is in use on the page.\n *\n * @return {Array}\n * an array of versions that are available.\n */\nFlash.version = function () {\n var version$$1 = '0,0,0';\n\n // IE\n try {\n version$$1 = new window_1.ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\\D+/g, ',').match(/^,?(.+),?$/)[1];\n\n // other browsers\n } catch (e) {\n try {\n if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {\n version$$1 = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\\D+/g, ',').match(/^,?(.+),?$/)[1];\n }\n } catch (err) {\n // satisfy linter\n }\n }\n return version$$1.split(',');\n};\n\n/**\n * Only use for non-iframe embeds.\n *\n * @param {Object} swf\n * The videojs-swf object.\n *\n * @param {Object} flashVars\n * Names and values to use as flash option variables.\n *\n * @param {Object} params\n * Style parameters to set on the object.\n *\n * @param {Object} attributes\n * Attributes to set on the element.\n *\n * @return {Element}\n * The embeded Flash DOM element.\n */\nFlash.embed = function (swf, flashVars, params, attributes) {\n var code = Flash.getEmbedCode(swf, flashVars, params, attributes);\n\n // Get element by embedding code and retrieving created element\n var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0];\n\n return obj;\n};\n\n/**\n * Only use for non-iframe embeds.\n *\n * @param {Object} swf\n * The videojs-swf object.\n *\n * @param {Object} flashVars\n * Names and values to use as flash option variables.\n *\n * @param {Object} params\n * Style parameters to set on the object.\n *\n * @param {Object} attributes\n * Attributes to set on the element.\n *\n * @return {Element}\n * The embeded Flash DOM element.\n */\nFlash.getEmbedCode = function (swf, flashVars, params, attributes) {\n var objTag = '';\n });\n\n attributes = mergeOptions({\n // Add swf to attributes (need both for IE and Others to work)\n data: swf,\n\n // Default to 100% width/height\n width: '100%',\n height: '100%'\n\n }, attributes);\n\n // Create Attributes string\n Object.getOwnPropertyNames(attributes).forEach(function (key) {\n attrsString += key + '=\"' + attributes[key] + '\" ';\n });\n\n return '' + objTag + attrsString + '>' + paramsString + '';\n};\n\n// Run Flash through the RTMP decorator\nFlashRtmpDecorator(Flash);\n\nif (Tech.getTech('Flash')) {\n videojs.log.warn('Not using videojs-flash as it appears to already be registered');\n videojs.log.warn('videojs-flash should only be used with video.js@6 and above');\n} else {\n videojs.registerTech('Flash', Flash);\n}\n\nFlash.VERSION = version$1;\n\nreturn Flash;\n\n})));\n"],"file":"videojs-flash-lazy.min.js"} \ No newline at end of file diff --git a/media/player/videojs/amd/src/loader.js b/media/player/videojs/amd/src/loader.js index 56b6bc25d87..6cd2dee6570 100644 --- a/media/player/videojs/amd/src/loader.js +++ b/media/player/videojs/amd/src/loader.js @@ -24,7 +24,6 @@ */ import Ajax from 'core/ajax'; -import Config from 'core/config'; import {eventTypes} from 'core_filters/events'; import LocalStorage from 'core/localstorage'; import Notification from 'core/notification'; @@ -88,14 +87,10 @@ const notifyVideoJS = e => { // Add YouTube to the list of modules we require. modulePromises.push(import('media_videojs/Youtube-lazy')); } - if (config.techOrder && config.techOrder.indexOf('flash') !== -1) { - // Add Flash to the list of modules we require. - modulePromises.push(import('media_videojs/videojs-flash-lazy')); - } + Promise.all([langStrings, ...modulePromises]) .then(([langJson, videojs]) => { if (firstLoad) { - videojs.options.flash.swf = `${Config.wwwroot}/media/player/videojs/videojs/video-js.swf`; videojs.options.playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]; videojs.options.userActions = { hotkeys: true, diff --git a/media/player/videojs/amd/src/videojs-flash-lazy.js b/media/player/videojs/amd/src/videojs-flash-lazy.js deleted file mode 100644 index c72260ac2f9..00000000000 --- a/media/player/videojs/amd/src/videojs-flash-lazy.js +++ /dev/null @@ -1,1455 +0,0 @@ -/** - * videojs-flash - * @version 2.2.1 - * @copyright 2020 Brightcove, Inc. - * @license Apache-2.0 - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) : - typeof define === 'function' && define.amd ? define(['media_videojs/video-lazy'], factory) : - (global.videojsFlash = factory(global.videojs)); -}(this, (function (videojs) { 'use strict'; - -videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs; - -var version = "5.4.2"; - -var version$1 = "2.2.1"; - -/** - * @file flash-rtmp.js - * @module flash-rtmp - */ - -/** - * Add RTMP properties to the {@link Flash} Tech. - * - * @param {Flash} Flash - * The flash tech class. - * - * @mixin FlashRtmpDecorator - * - * @return {Flash} - * The flash tech with RTMP properties added. - */ -function FlashRtmpDecorator(Flash) { - Flash.streamingFormats = { - 'rtmp/mp4': 'MP4', - 'rtmp/flv': 'FLV' - }; - - /** - * Join connection and stream with an ampersand. - * - * @param {string} connection - * The connection string. - * - * @param {string} stream - * The stream string. - * - * @return {string} - * The connection and stream joined with an `&` character - */ - Flash.streamFromParts = function (connection, stream) { - return connection + '&' + stream; - }; - - /** - * The flash parts object that contains connection and stream info. - * - * @typedef {Object} Flash~PartsObject - * - * @property {string} connection - * The connection string of a source, defaults to an empty string. - * - * @property {string} stream - * The stream string of the source, defaults to an empty string. - */ - - /** - * Convert a source url into a stream and connection parts. - * - * @param {string} src - * the source url - * - * @return {Flash~PartsObject} - * The parts object that contains a connection and a stream - */ - Flash.streamToParts = function (src) { - var parts = { - connection: '', - stream: '' - }; - - if (!src) { - return parts; - } - - // Look for the normal URL separator we expect, '&'. - // If found, we split the URL into two pieces around the - // first '&'. - var connEnd = src.search(/&(?![\w-]+=)/); - var streamBegin = void 0; - - if (connEnd !== -1) { - streamBegin = connEnd + 1; - } else { - // If there's not a '&', we use the last '/' as the delimiter. - connEnd = streamBegin = src.lastIndexOf('/') + 1; - if (connEnd === 0) { - // really, there's not a '/'? - connEnd = streamBegin = src.length; - } - } - - parts.connection = src.substring(0, connEnd); - parts.stream = src.substring(streamBegin, src.length); - - return parts; - }; - - /** - * Check if the source type is a streaming type. - * - * @param {string} srcType - * The mime type to check. - * - * @return {boolean} - * - True if the source type is a streaming type. - * - False if the source type is not a streaming type. - */ - Flash.isStreamingType = function (srcType) { - return srcType in Flash.streamingFormats; - }; - - // RTMP has four variations, any string starting - // with one of these protocols should be valid - - /** - * Regular expression used to check if the source is an rtmp source. - * - * @property {RegExp} Flash.RTMP_RE - */ - Flash.RTMP_RE = /^rtmp[set]?:\/\//i; - - /** - * Check if the source itself is a streaming type. - * - * @param {string} src - * The url to the source. - * - * @return {boolean} - * - True if the source url indicates that the source is streaming. - * - False if the shource url indicates that the source url is not streaming. - */ - Flash.isStreamingSrc = function (src) { - return Flash.RTMP_RE.test(src); - }; - - /** - * A source handler for RTMP urls - * @type {Object} - */ - Flash.rtmpSourceHandler = {}; - - /** - * Check if Flash can play the given mime type. - * - * @param {string} type - * The mime type to check - * - * @return {string} - * 'maybe', or '' (empty string) - */ - Flash.rtmpSourceHandler.canPlayType = function (type) { - if (Flash.isStreamingType(type)) { - return 'maybe'; - } - - return ''; - }; - - /** - * Check if Flash can handle the source natively - * - * @param {Object} source - * The source object - * - * @param {Object} [options] - * The options passed to the tech - * - * @return {string} - * 'maybe', or '' (empty string) - */ - Flash.rtmpSourceHandler.canHandleSource = function (source, options) { - var can = Flash.rtmpSourceHandler.canPlayType(source.type); - - if (can) { - return can; - } - - if (Flash.isStreamingSrc(source.src)) { - return 'maybe'; - } - - return ''; - }; - - /** - * Pass the source to the flash object. - * - * @param {Object} source - * The source object - * - * @param {Flash} tech - * The instance of the Flash tech - * - * @param {Object} [options] - * The options to pass to the source - */ - Flash.rtmpSourceHandler.handleSource = function (source, tech, options) { - var srcParts = Flash.streamToParts(source.src); - - tech.setRtmpConnection(srcParts.connection); - tech.setRtmpStream(srcParts.stream); - }; - - // Register the native source handler - Flash.registerSourceHandler(Flash.rtmpSourceHandler); - - return Flash; -} - -var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - -var win; - -if (typeof window !== "undefined") { - win = window; -} else if (typeof commonjsGlobal !== "undefined") { - win = commonjsGlobal; -} else if (typeof self !== "undefined"){ - win = self; -} else { - win = {}; -} - -var window_1 = win; - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var inherits = function (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 possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return call && (typeof call === "object" || typeof call === "function") ? call : self; -}; - -/** - * @file flash.js - * VideoJS-SWF - Custom Flash Player with HTML5-ish API - * https://github.com/zencoder/video-js-swf - * Not using setupTriggers. Using global onEvent func to distribute events - */ - -var Tech = videojs.getComponent('Tech'); -var Dom = videojs.dom; -var Url = videojs.url; -var createTimeRange = videojs.createTimeRange; -var mergeOptions = videojs.mergeOptions; - -var navigator = window_1 && window_1.navigator || {}; - -/** - * Flash Media Controller - Wrapper for Flash Media API - * - * @mixes FlashRtmpDecorator - * @mixes Tech~SouceHandlerAdditions - * @extends Tech - */ - -var Flash = function (_Tech) { - inherits(Flash, _Tech); - - /** - * Create an instance of this Tech. - * - * @param {Object} [options] - * The key/value store of player options. - * - * @param {Component~ReadyCallback} ready - * Callback function to call when the `Flash` Tech is ready. - */ - function Flash(options, ready) { - classCallCheck(this, Flash); - - // Set the source when ready - var _this = possibleConstructorReturn(this, _Tech.call(this, options, ready)); - - if (options.source) { - _this.ready(function () { - this.setSource(options.source); - }, true); - } - - // Having issues with Flash reloading on certain page actions - // (hide/resize/fullscreen) in certain browsers - // This allows resetting the playhead when we catch the reload - if (options.startTime) { - _this.ready(function () { - this.load(); - this.play(); - this.currentTime(options.startTime); - }, true); - } - - // Add global window functions that the swf expects - // A 4.x workflow we weren't able to solve for in 5.0 - // because of the need to hard code these functions - // into the swf for security reasons - window_1.videojs = window_1.videojs || {}; - window_1.videojs.Flash = window_1.videojs.Flash || {}; - window_1.videojs.Flash.onReady = Flash.onReady; - window_1.videojs.Flash.onEvent = Flash.onEvent; - window_1.videojs.Flash.onError = Flash.onError; - - _this.on('seeked', function () { - this.lastSeekTarget_ = undefined; - }); - - return _this; - } - - /** - * Create the `Flash` Tech's DOM element. - * - * @return {Element} - * The element that gets created. - */ - - - Flash.prototype.createEl = function createEl() { - var options = this.options_; - - // If video.js is hosted locally you should also set the location - // for the hosted swf, which should be relative to the page (not video.js) - // Otherwise this adds a CDN url. - // The CDN also auto-adds a swf URL for that specific version. - if (!options.swf) { - options.swf = 'https://vjs.zencdn.net/swf/' + version + '/video-js.swf'; - } - - // Generate ID for swf object - var objId = options.techId; - - // Merge default flashvars with ones passed in to init - var flashVars = mergeOptions({ - - // SWF Callback Functions - readyFunction: 'videojs.Flash.onReady', - eventProxyFunction: 'videojs.Flash.onEvent', - errorEventProxyFunction: 'videojs.Flash.onError', - - // Player Settings - autoplay: options.autoplay, - preload: options.preload, - loop: options.loop, - muted: options.muted - - }, options.flashVars); - - // Merge default parames with ones passed in - var params = mergeOptions({ - // Opaque is needed to overlay controls, but can affect playback performance - wmode: 'opaque', - // Using bgcolor prevents a white flash when the object is loading - bgcolor: '#000000' - }, options.params); - - // Merge default attributes with ones passed in - var attributes = mergeOptions({ - // Both ID and Name needed or swf to identify itself - id: objId, - name: objId, - 'class': 'vjs-tech' - }, options.attributes); - - this.el_ = Flash.embed(options.swf, flashVars, params, attributes); - this.el_.tech = this; - - return this.el_; - }; - - /** - * Called by {@link Player#play} to play using the `Flash` `Tech`. - */ - - - Flash.prototype.play = function play() { - if (this.ended()) { - this.setCurrentTime(0); - } - this.el_.vjs_play(); - }; - - /** - * Called by {@link Player#pause} to pause using the `Flash` `Tech`. - */ - - - Flash.prototype.pause = function pause() { - this.el_.vjs_pause(); - }; - - /** - * A getter/setter for the `Flash` Tech's source object. - * > Note: Please use {@link Flash#setSource} - * - * @param {Tech~SourceObject} [src] - * The source object you want to set on the `Flash` techs. - * - * @return {Tech~SourceObject|undefined} - * - The current source object when a source is not passed in. - * - undefined when setting - * - * @deprecated Since version 5. - */ - - - Flash.prototype.src = function src(_src) { - if (_src === undefined) { - return this.currentSrc(); - } - - // Setting src through `src` not `setSrc` will be deprecated - return this.setSrc(_src); - }; - - /** - * A getter/setter for the `Flash` Tech's source object. - * - * @param {Tech~SourceObject} [src] - * The source object you want to set on the `Flash` techs. - */ - - - Flash.prototype.setSrc = function setSrc(src) { - var _this2 = this; - - // Make sure source URL is absolute. - src = Url.getAbsoluteURL(src); - this.el_.vjs_src(src); - - // Currently the SWF doesn't autoplay if you load a source later. - // e.g. Load player w/ no source, wait 2s, set src. - if (this.autoplay()) { - this.setTimeout(function () { - return _this2.play(); - }, 0); - } - }; - - /** - * Indicates whether the media is currently seeking to a new position or not. - * - * @return {boolean} - * - True if seeking to a new position - * - False otherwise - */ - - - Flash.prototype.seeking = function seeking() { - return this.lastSeekTarget_ !== undefined; - }; - - /** - * Returns the current time in seconds that the media is at in playback. - * - * @param {number} time - * Current playtime of the media in seconds. - */ - - - Flash.prototype.setCurrentTime = function setCurrentTime(time) { - var seekable = this.seekable(); - - if (seekable.length) { - // clamp to the current seekable range - time = time > seekable.start(0) ? time : seekable.start(0); - time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); - - this.lastSeekTarget_ = time; - this.trigger('seeking'); - this.el_.vjs_setProperty('currentTime', time); - _Tech.prototype.setCurrentTime.call(this); - } - }; - - /** - * Get the current playback time in seconds - * - * @return {number} - * The current time of playback in seconds. - */ - - - Flash.prototype.currentTime = function currentTime() { - // when seeking make the reported time keep up with the requested time - // by reading the time we're seeking to - if (this.seeking()) { - return this.lastSeekTarget_ || 0; - } - return this.el_.vjs_getProperty('currentTime'); - }; - - /** - * Get the current source - * - * @method currentSrc - * @return {Tech~SourceObject} - * The current source - */ - - - Flash.prototype.currentSrc = function currentSrc() { - if (this.currentSource_) { - return this.currentSource_.src; - } - return this.el_.vjs_getProperty('currentSrc'); - }; - - /** - * Get the total duration of the current media. - * - * @return {number} - 8 The total duration of the current media. - */ - - - Flash.prototype.duration = function duration() { - if (this.readyState() === 0) { - return NaN; - } - var duration = this.el_.vjs_getProperty('duration'); - - return duration >= 0 ? duration : Infinity; - }; - - /** - * Load media into Tech. - */ - - - Flash.prototype.load = function load() { - this.el_.vjs_load(); - }; - - /** - * Get the poster image that was set on the tech. - */ - - - Flash.prototype.poster = function poster() { - this.el_.vjs_getProperty('poster'); - }; - - /** - * Poster images are not handled by the Flash tech so make this is a no-op. - */ - - - Flash.prototype.setPoster = function setPoster() {}; - - /** - * Determine the time ranges that can be seeked to in the media. - * - * @return {TimeRange} - * Returns the time ranges that can be seeked to. - */ - - - Flash.prototype.seekable = function seekable() { - var duration = this.duration(); - - if (duration === 0) { - return createTimeRange(); - } - return createTimeRange(0, duration); - }; - - /** - * Get and create a `TimeRange` object for buffering. - * - * @return {TimeRange} - * The time range object that was created. - */ - - - Flash.prototype.buffered = function buffered() { - var ranges = this.el_.vjs_getProperty('buffered'); - - if (ranges.length === 0) { - return createTimeRange(); - } - return createTimeRange(ranges[0][0], ranges[0][1]); - }; - - /** - * Get fullscreen support - - * - * Flash does not allow fullscreen through javascript - * so this always returns false. - * - * @return {boolean} - * The Flash tech does not support fullscreen, so it will always return false. - */ - - - Flash.prototype.supportsFullScreen = function supportsFullScreen() { - // Flash does not allow fullscreen through javascript - return false; - }; - - /** - * Flash does not allow fullscreen through javascript - * so this always returns false. - * - * @return {boolean} - * The Flash tech does not support fullscreen, so it will always return false. - */ - - - Flash.prototype.enterFullScreen = function enterFullScreen() { - return false; - }; - - /** - * Gets available media playback quality metrics as specified by the W3C's Media - * Playback Quality API. - * - * @see [Spec]{@link https://wicg.github.io/media-playback-quality} - * - * @return {Object} - * An object with supported media playback quality metrics - */ - - - Flash.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { - var videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality'); - - if (window_1.performance && typeof window_1.performance.now === 'function') { - videoPlaybackQuality.creationTime = window_1.performance.now(); - } else if (window_1.performance && window_1.performance.timing && typeof window_1.performance.timing.navigationStart === 'number') { - videoPlaybackQuality.creationTime = window_1.Date.now() - window_1.performance.timing.navigationStart; - } - - return videoPlaybackQuality; - }; - - return Flash; -}(Tech); - -// Create setters and getters for attributes - - -var _readWrite = ['rtmpConnection', 'rtmpStream', 'preload', 'defaultPlaybackRate', 'playbackRate', 'autoplay', 'loop', 'controls', 'volume', 'muted', 'defaultMuted']; -var _readOnly = ['networkState', 'readyState', 'initialTime', 'startOffsetTime', 'paused', 'ended', 'videoWidth', 'videoHeight']; -var _api = Flash.prototype; - -/** - * Create setters for the swf on the element - * - * @param {string} attr - * The name of the parameter - * - * @private - */ -function _createSetter(attr) { - var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1); - - _api['set' + attrUpper] = function (val) { - return this.el_.vjs_setProperty(attr, val); - }; -} - -/** - * Create getters for the swf on the element - * - * @param {string} attr - * The name of the parameter - * - * @private - */ -function _createGetter(attr) { - _api[attr] = function () { - return this.el_.vjs_getProperty(attr); - }; -} - -// Create getter and setters for all read/write attributes -for (var i = 0; i < _readWrite.length; i++) { - _createGetter(_readWrite[i]); - _createSetter(_readWrite[i]); -} - -// Create getters for read-only attributes -for (var _i = 0; _i < _readOnly.length; _i++) { - _createGetter(_readOnly[_i]); -} - -/** ------------------------------ Getters ------------------------------ **/ -/** - * Get the value of `rtmpConnection` from the swf. - * - * @method Flash#rtmpConnection - * @return {string} - * The current value of `rtmpConnection` on the swf. - */ - -/** - * Get the value of `rtmpStream` from the swf. - * - * @method Flash#rtmpStream - * @return {string} - * The current value of `rtmpStream` on the swf. - */ - -/** - * Get the value of `preload` from the swf. `preload` indicates - * what should download before the media is interacted with. It can have the following - * values: - * - none: nothing should be downloaded - * - metadata: poster and the first few frames of the media may be downloaded to get - * media dimensions and other metadata - * - auto: allow the media and metadata for the media to be downloaded before - * interaction - * - * @method Flash#preload - * @return {string} - * The value of `preload` from the swf. Will be 'none', 'metadata', - * or 'auto'. - */ - -/** - * Get the value of `defaultPlaybackRate` from the swf. - * - * @method Flash#defaultPlaybackRate - * @return {number} - * The current value of `defaultPlaybackRate` on the swf. - */ - -/** - * Get the value of `playbackRate` from the swf. `playbackRate` indicates - * the rate at which the media is currently playing back. Examples: - * - if playbackRate is set to 2, media will play twice as fast. - * - if playbackRate is set to 0.5, media will play half as fast. - * - * @method Flash#playbackRate - * @return {number} - * The value of `playbackRate` from the swf. A number indicating - * the current playback speed of the media, where 1 is normal speed. - */ - -/** - * Get the value of `autoplay` from the swf. `autoplay` indicates - * that the media should start to play as soon as the page is ready. - * - * @method Flash#autoplay - * @return {boolean} - * - The value of `autoplay` from the swf. - * - True indicates that the media ashould start as soon as the page loads. - * - False indicates that the media should not start as soon as the page loads. - */ - -/** - * Get the value of `loop` from the swf. `loop` indicates - * that the media should return to the start of the media and continue playing once - * it reaches the end. - * - * @method Flash#loop - * @return {boolean} - * - The value of `loop` from the swf. - * - True indicates that playback should seek back to start once - * the end of a media is reached. - * - False indicates that playback should not loop back to the start when the - * end of the media is reached. - */ - -/** - * Get the value of `mediaGroup` from the swf. - * - * @method Flash#mediaGroup - * @return {string} - * The current value of `mediaGroup` on the swf. - */ - -/** - * Get the value of `controller` from the swf. - * - * @method Flash#controller - * @return {string} - * The current value of `controller` on the swf. - */ - -/** - * Get the value of `controls` from the swf. `controls` indicates - * whether the native flash controls should be shown or hidden. - * - * @method Flash#controls - * @return {boolean} - * - The value of `controls` from the swf. - * - True indicates that native controls should be showing. - * - False indicates that native controls should be hidden. - */ - -/** - * Get the value of the `volume` from the swf. `volume` indicates the current - * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and - * so on. - * - * @method Flash#volume - * @return {number} - * The volume percent as a decimal. Value will be between 0-1. - */ - -/** - * Get the value of the `muted` from the swf. `muted` indicates the current - * audio level should be silent. - * - * @method Flash#muted - * @return {boolean} - * - True if the audio should be set to silent - * - False otherwise - */ - -/** - * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates - * whether the media should start muted or not. Only changes the default state of the - * media. `muted` and `defaultMuted` can have different values. `muted` indicates the - * current state. - * - * @method Flash#defaultMuted - * @return {boolean} - * - The value of `defaultMuted` from the swf. - * - True indicates that the media should start muted. - * - False indicates that the media should not start muted. - */ - -/** - * Get the value of `networkState` from the swf. `networkState` indicates - * the current network state. It returns an enumeration from the following list: - * - 0: NETWORK_EMPTY - * - 1: NEWORK_IDLE - * - 2: NETWORK_LOADING - * - 3: NETWORK_NO_SOURCE - * - * @method Flash#networkState - * @return {number} - * The value of `networkState` from the swf. This will be a number - * from the list in the description. - */ - -/** - * Get the value of `readyState` from the swf. `readyState` indicates - * the current state of the media element. It returns an enumeration from the - * following list: - * - 0: HAVE_NOTHING - * - 1: HAVE_METADATA - * - 2: HAVE_CURRENT_DATA - * - 3: HAVE_FUTURE_DATA - * - 4: HAVE_ENOUGH_DATA - * - * @method Flash#readyState - * @return {number} - * The value of `readyState` from the swf. This will be a number - * from the list in the description. - */ - -/** - * Get the value of `readyState` from the swf. `readyState` indicates - * the current state of the media element. It returns an enumeration from the - * following list: - * - 0: HAVE_NOTHING - * - 1: HAVE_METADATA - * - 2: HAVE_CURRENT_DATA - * - 3: HAVE_FUTURE_DATA - * - 4: HAVE_ENOUGH_DATA - * - * @method Flash#readyState - * @return {number} - * The value of `readyState` from the swf. This will be a number - * from the list in the description. - */ - -/** - * Get the value of `initialTime` from the swf. - * - * @method Flash#initialTime - * @return {number} - * The `initialTime` proprety on the swf. - */ - -/** - * Get the value of `startOffsetTime` from the swf. - * - * @method Flash#startOffsetTime - * @return {number} - * The `startOffsetTime` proprety on the swf. - */ - -/** - * Get the value of `paused` from the swf. `paused` indicates whether the swf - * is current paused or not. - * - * @method Flash#paused - * @return {boolean} - * The value of `paused` from the swf. - */ - -/** - * Get the value of `ended` from the swf. `ended` indicates whether - * the media has reached the end or not. - * - * @method Flash#ended - * @return {boolean} - * - True indicates that the media has ended. - * - False indicates that the media has not ended. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} - */ - -/** - * Get the value of `videoWidth` from the swf. `videoWidth` indicates - * the current width of the media in css pixels. - * - * @method Flash#videoWidth - * @return {number} - * The value of `videoWidth` from the swf. This will be a number - * in css pixels. - */ - -/** - * Get the value of `videoHeight` from the swf. `videoHeigth` indicates - * the current height of the media in css pixels. - * - * @method Flassh.prototype.videoHeight - * @return {number} - * The value of `videoHeight` from the swf. This will be a number - * in css pixels. - */ -/** ------------------------------ Setters ------------------------------ **/ - -/** - * Set the value of `rtmpConnection` on the swf. - * - * @method Flash#setRtmpConnection - * @param {string} rtmpConnection - * New value to set the `rtmpConnection` property to. - */ - -/** - * Set the value of `rtmpStream` on the swf. - * - * @method Flash#setRtmpStream - * @param {string} rtmpStream - * New value to set the `rtmpStream` property to. - */ - -/** - * Set the value of `preload` on the swf. `preload` indicates - * what should download before the media is interacted with. It can have the following - * values: - * - none: nothing should be downloaded - * - metadata: poster and the first few frames of the media may be downloaded to get - * media dimensions and other metadata - * - auto: allow the media and metadata for the media to be downloaded before - * interaction - * - * @method Flash#setPreload - * @param {string} preload - * The value of `preload` to set on the swf. Should be 'none', 'metadata', - * or 'auto'. - */ - -/** - * Set the value of `defaultPlaybackRate` on the swf. - * - * @method Flash#setDefaultPlaybackRate - * @param {number} defaultPlaybackRate - * New value to set the `defaultPlaybackRate` property to. - */ - -/** - * Set the value of `playbackRate` on the swf. `playbackRate` indicates - * the rate at which the media is currently playing back. Examples: - * - if playbackRate is set to 2, media will play twice as fast. - * - if playbackRate is set to 0.5, media will play half as fast. - * - * @method Flash#setPlaybackRate - * @param {number} playbackRate - * New value of `playbackRate` on the swf. A number indicating - * the current playback speed of the media, where 1 is normal speed. - */ - -/** - * Set the value of `autoplay` on the swf. `autoplay` indicates - * that the media should start to play as soon as the page is ready. - * - * @method Flash#setAutoplay - * @param {boolean} autoplay - * - The value of `autoplay` from the swf. - * - True indicates that the media ashould start as soon as the page loads. - * - False indicates that the media should not start as soon as the page loads. - */ - -/** - * Set the value of `loop` on the swf. `loop` indicates - * that the media should return to the start of the media and continue playing once - * it reaches the end. - * - * @method Flash#setLoop - * @param {boolean} loop - * - True indicates that playback should seek back to start once - * the end of a media is reached. - * - False indicates that playback should not loop back to the start when the - * end of the media is reached. - */ - -/** - * Set the value of `mediaGroup` on the swf. - * - * @method Flash#setMediaGroup - * @param {string} mediaGroup - * New value of `mediaGroup` to set on the swf. - */ - -/** - * Set the value of `controller` on the swf. - * - * @method Flash#setController - * @param {string} controller - * New value the current value of `controller` on the swf. - */ - -/** - * Get the value of `controls` from the swf. `controls` indicates - * whether the native flash controls should be shown or hidden. - * - * @method Flash#controls - * @return {boolean} - * - The value of `controls` from the swf. - * - True indicates that native controls should be showing. - * - False indicates that native controls should be hidden. - */ - -/** - * Set the value of the `volume` on the swf. `volume` indicates the current - * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and - * so on. - * - * @method Flash#setVolume - * @param {number} percentAsDecimal - * The volume percent as a decimal. Value will be between 0-1. - */ - -/** - * Set the value of the `muted` on the swf. `muted` indicates that the current - * audio level should be silent. - * - * @method Flash#setMuted - * @param {boolean} muted - * - True if the audio should be set to silent - * - False otherwise - */ - -/** - * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates - * whether the media should start muted or not. Only changes the default state of the - * media. `muted` and `defaultMuted` can have different values. `muted` indicates the - * current state. - * - * @method Flash#setDefaultMuted - * @param {boolean} defaultMuted - * - True indicates that the media should start muted. - * - False indicates that the media should not start muted. - */ - -/* Flash Support Testing -------------------------------------------------------- */ - -/** - * Check if the Flash tech is currently supported. - * - * @return {boolean} - * - True for Chrome and Safari Desktop and Microsoft Edge and if flash tech is supported - * - False otherwise - */ -Flash.isSupported = function () { - // for Chrome Desktop and Safari Desktop - if (videojs.browser.IS_CHROME && (!videojs.browser.IS_ANDROID || !videojs.browser.IS_IOS) || videojs.browser.IS_SAFARI && !videojs.browser.IS_IOS || videojs.browser.IS_EDGE) { - return true; - } - // for other browsers - return Flash.version()[0] >= 10; -}; - -// Add Source Handler pattern functions to this tech -Tech.withSourceHandlers(Flash); - -/* - * Native source handler for flash, simply passes the source to the swf element. - * - * @property {Tech~SourceObject} source - * The source object - * - * @property {Flash} tech - * The instance of the Flash tech - */ -Flash.nativeSourceHandler = {}; - -/** - * Check if the Flash can play the given mime type. - * - * @param {string} type - * The mimetype to check - * - * @return {string} - * 'maybe', or '' (empty string) - */ -Flash.nativeSourceHandler.canPlayType = function (type) { - if (type in Flash.formats) { - return 'maybe'; - } - - return ''; -}; - -/** - * Check if the media element can handle a source natively. - * - * @param {Tech~SourceObject} source - * The source object - * - * @param {Object} [options] - * Options to be passed to the tech. - * - * @return {string} - * 'maybe', or '' (empty string). - */ -Flash.nativeSourceHandler.canHandleSource = function (source, options) { - var type = void 0; - - /** - * Guess the mime type of a file if it does not have one - * - * @param {Tech~SourceObject} src - * The source object to guess the mime type for - * - * @return {string} - * The mime type that was guessed - */ - function guessMimeType(src) { - var ext = Url.getFileExtension(src); - - if (ext) { - return 'video/' + ext; - } - return ''; - } - - if (!source.type) { - type = guessMimeType(source.src); - } else { - // Strip code information from the type because we don't get that specific - type = source.type.replace(/;.*/, '').toLowerCase(); - } - - return Flash.nativeSourceHandler.canPlayType(type); -}; - -/** - * Pass the source to the swf. - * - * @param {Tech~SourceObject} source - * The source object - * - * @param {Flash} tech - * The instance of the Flash tech - * - * @param {Object} [options] - * The options to pass to the source - */ -Flash.nativeSourceHandler.handleSource = function (source, tech, options) { - tech.setSrc(source.src); -}; - -/** - * noop for native source handler dispose, as cleanup will happen automatically. - */ -Flash.nativeSourceHandler.dispose = function () {}; - -// Register the native source handler -Flash.registerSourceHandler(Flash.nativeSourceHandler); - -/** - * Flash supported mime types. - * - * @constant {Object} - */ -Flash.formats = { - 'video/flv': 'FLV', - 'video/x-flv': 'FLV', - 'video/mp4': 'MP4', - 'video/m4v': 'MP4' -}; - -/** - * Called when the the swf is "ready", and makes sure that the swf is really - * ready using {@link Flash#checkReady} - * - * @param {Object} currSwf - * The current swf object - */ -Flash.onReady = function (currSwf) { - var el = Dom.$('#' + currSwf); - var tech = el && el.tech; - - // if there is no el then the tech has been disposed - // and the tech element was removed from the player div - if (tech && tech.el()) { - // check that the flash object is really ready - Flash.checkReady(tech); - } -}; - -/** - * The SWF isn't always ready when it says it is. Sometimes the API functions still - * need to be added to the object. If it's not ready, we set a timeout to check again - * shortly. - * - * @param {Flash} tech - * The instance of the flash tech to check. - */ -Flash.checkReady = function (tech) { - // stop worrying if the tech has been disposed - if (!tech.el()) { - return; - } - - // check if API property exists - if (tech.el().vjs_getProperty) { - // tell tech it's ready - tech.triggerReady(); - } else { - // wait longer - this.setTimeout(function () { - Flash.checkReady(tech); - }, 50); - } -}; - -/** - * Trigger events from the swf on the Flash Tech. - * - * @param {number} swfID - * The id of the swf that had the event - * - * @param {string} eventName - * The name of the event to trigger - */ -Flash.onEvent = function (swfID, eventName) { - var tech = Dom.$('#' + swfID).tech; - var args = Array.prototype.slice.call(arguments, 2); - - // dispatch Flash events asynchronously for two reasons: - // - Flash swallows any exceptions generated by javascript it - // invokes - // - Flash is suspended until the javascript returns which may cause - // playback performance issues - tech.setTimeout(function () { - tech.trigger(eventName, args); - }, 1); -}; - -/** - * Log errors from the swf on the Flash tech. - * - * @param {number} swfID - * The id of the swf that had an error. - * - * @param {string} err - * The error to set on the Flash Tech. - * - * @return {MediaError|undefined} - * - Returns a MediaError when err is 'srcnotfound' - * - Returns undefined otherwise. - */ -Flash.onError = function (swfID, err) { - var tech = Dom.$('#' + swfID).tech; - - // trigger MEDIA_ERR_SRC_NOT_SUPPORTED - if (err === 'srcnotfound') { - return tech.error(4); - } - - // trigger a custom error - if (typeof err === 'string') { - tech.error('FLASH: ' + err); - } else { - err.origin = 'flash'; - tech.error(err); - } -}; - -/** - * Get the current version of Flash that is in use on the page. - * - * @return {Array} - * an array of versions that are available. - */ -Flash.version = function () { - var version$$1 = '0,0,0'; - - // IE - try { - version$$1 = new window_1.ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; - - // other browsers - } catch (e) { - try { - if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) { - version$$1 = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; - } - } catch (err) { - // satisfy linter - } - } - return version$$1.split(','); -}; - -/** - * Only use for non-iframe embeds. - * - * @param {Object} swf - * The videojs-swf object. - * - * @param {Object} flashVars - * Names and values to use as flash option variables. - * - * @param {Object} params - * Style parameters to set on the object. - * - * @param {Object} attributes - * Attributes to set on the element. - * - * @return {Element} - * The embeded Flash DOM element. - */ -Flash.embed = function (swf, flashVars, params, attributes) { - var code = Flash.getEmbedCode(swf, flashVars, params, attributes); - - // Get element by embedding code and retrieving created element - var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0]; - - return obj; -}; - -/** - * Only use for non-iframe embeds. - * - * @param {Object} swf - * The videojs-swf object. - * - * @param {Object} flashVars - * Names and values to use as flash option variables. - * - * @param {Object} params - * Style parameters to set on the object. - * - * @param {Object} attributes - * Attributes to set on the element. - * - * @return {Element} - * The embeded Flash DOM element. - */ -Flash.getEmbedCode = function (swf, flashVars, params, attributes) { - var objTag = ''; - }); - - attributes = mergeOptions({ - // Add swf to attributes (need both for IE and Others to work) - data: swf, - - // Default to 100% width/height - width: '100%', - height: '100%' - - }, attributes); - - // Create Attributes string - Object.getOwnPropertyNames(attributes).forEach(function (key) { - attrsString += key + '="' + attributes[key] + '" '; - }); - - return '' + objTag + attrsString + '>' + paramsString + ''; -}; - -// Run Flash through the RTMP decorator -FlashRtmpDecorator(Flash); - -if (Tech.getTech('Flash')) { - videojs.log.warn('Not using videojs-flash as it appears to already be registered'); - videojs.log.warn('videojs-flash should only be used with video.js@6 and above'); -} else { - videojs.registerTech('Flash', Flash); -} - -Flash.VERSION = version$1; - -return Flash; - -}))); diff --git a/media/player/videojs/classes/plugin.php b/media/player/videojs/classes/plugin.php index 1eb79c07ec2..2c2e5a2b6de 100644 --- a/media/player/videojs/classes/plugin.php +++ b/media/player/videojs/classes/plugin.php @@ -72,10 +72,8 @@ class media_videojs_plugin extends core_media_player_native { $hasposter = self::get_attribute($text, 'poster') !== null; } - // Currently Flash in VideoJS does not support responsive layout. If Flash is enabled try to guess - // if HTML5 player will be engaged for the user and then set it to responsive. - $responsive = (get_config('media_videojs', 'useflash') && !$this->youtube) ? null : true; - $flashtech = false; + // Try to guess if HTML5 player will be engaged for the user and then set it to responsive. + $responsive = (!$this->youtube) ? null : true; // Build list of source tags. foreach ($urls as $url) { @@ -101,10 +99,6 @@ class media_videojs_plugin extends core_media_player_native { if ($responsive === null) { $responsive = core_useragent::supports_html5($extension); } - if (($url->get_scheme() === 'rtmp' || !core_useragent::supports_html5($extension)) - && get_config('media_videojs', 'useflash')) { - $flashtech = true; - } } $sources = implode("\n", $sources); @@ -123,8 +117,6 @@ class media_videojs_plugin extends core_media_player_native { $sources = ''; // Do not specify tags - it may confuse browser. $isaudio = false; // Just in case. - } else if ($flashtech) { - $datasetup[] = '"techOrder": ["flash", "html5"]'; } // Add a language. @@ -258,8 +250,8 @@ class media_videojs_plugin extends core_media_player_native { get_config('media_videojs', 'audioextensions')))); $this->extensions = file_get_typegroup('extension', $filetypes); - if ($this->extensions && !get_config('media_videojs', 'useflash')) { - // If Flash is disabled get extensions supported by player that don't rely on flash. + if ($this->extensions) { + // Get extensions supported by player. $supportedextensions = array_merge(file_get_typegroup('extension', 'html_video'), file_get_typegroup('extension', 'html_audio'), file_get_typegroup('extension', 'media_source')); $this->extensions = array_intersect($this->extensions, $supportedextensions); @@ -283,17 +275,9 @@ class media_videojs_plugin extends core_media_player_native { } $extensions = $this->get_supported_extensions(); - $rtmpallowed = get_config('media_videojs', 'rtmp') && get_config('media_videojs', 'useflash'); foreach ($urls as $url) { - // If RTMP support is disabled, skip the URL that is using RTMP (which - // might have been picked to the list by its valid extension). - if (!$rtmpallowed && ($url->get_scheme() === 'rtmp')) { - continue; - } - - // If RTMP support is allowed, URL with RTMP scheme is supported irrespective to extension. - if ($rtmpallowed && ($url->get_scheme() === 'rtmp')) { - $result[] = $url; + // Skip the URL that is using RTMP (which might have been picked to the list by its valid extension). + if ($url->get_scheme() === 'rtmp') { continue; } @@ -305,15 +289,7 @@ class media_videojs_plugin extends core_media_player_native { continue; } - if (!get_config('media_videojs', 'useflash')) { - return parent::list_supported_urls($urls, $options); - } else { - // If Flash fallback is enabled we can not check if/when browser supports flash. - // We assume it will be able to handle any other extensions that player supports. - if (in_array($ext, $extensions)) { - $result[] = $url; - } - } + return parent::list_supported_urls($urls, $options); } return $result; } @@ -381,9 +357,6 @@ class media_videojs_plugin extends core_media_player_native { if (get_config('media_videojs', 'youtube')) { $supports .= ($supports ? '
' : '') . get_string('youtube', 'media_videojs'); } - if (get_config('media_videojs', 'rtmp') && get_config('media_videojs', 'useflash')) { - $supports .= ($supports ? '
' : '') . get_string('rtmp', 'media_videojs'); - } return $supports; } @@ -393,10 +366,6 @@ class media_videojs_plugin extends core_media_player_native { if (get_config('media_videojs', 'youtube')) { $markers = array_merge($markers, array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be')); } - // Add RTMP support if enabled. - if (get_config('media_videojs', 'rtmp') && get_config('media_videojs', 'useflash')) { - $markers[] = 'rtmp://'; - } return $markers; } diff --git a/media/player/videojs/db/upgrade.php b/media/player/videojs/db/upgrade.php new file mode 100644 index 00000000000..e9bbe4bb8b7 --- /dev/null +++ b/media/player/videojs/db/upgrade.php @@ -0,0 +1,66 @@ +. + +/** + * VideoJS media player upgrade code + * + * This file keeps track of upgrades to + * the videojs media player. + * + * Sometimes, changes between versions involve + * alterations to database structures and other + * major things that may break installations. + * + * The upgrade function in this file will attempt + * to perform all the necessary actions to upgrade + * your older installation to the current version. + * + * If there's something it cannot do itself, it + * will tell you what you need to do. + * + * The commands in here will all be database-neutral, + * using the methods of database_manager class + * + * Please do not forget to use upgrade_set_timeout() + * before any action that may take longer time to finish. + * + * @package media_videojs + * @copyright 2021 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * Main upgrade tasks to be executed on plugin version bump. + * + * @param int $oldversion + * @return bool always true + */ +function xmldb_media_videojs_upgrade($oldversion) { + global $CFG; + + if ($oldversion < 2021052503) { + // Remove useflash and rtmp settings. + unset_config('useflash', 'media_videojs'); + unset_config('rtmp', 'media_videojs'); + + // Main savepoint reached. + upgrade_plugin_savepoint(true, 2021052503, 'media', 'videojs'); + } + + return true; +} diff --git a/media/player/videojs/lang/en/deprecated.txt b/media/player/videojs/lang/en/deprecated.txt new file mode 100644 index 00000000000..f3abc1bd83b --- /dev/null +++ b/media/player/videojs/lang/en/deprecated.txt @@ -0,0 +1,4 @@ +configrtmp,media_videojs +configuseflash,media_videojs +rtmp,media_videojs +useflash,media_videojs diff --git a/media/player/videojs/lang/en/media_videojs.php b/media/player/videojs/lang/en/media_videojs.php index fcb48d7d05b..c608c2afe57 100644 --- a/media/player/videojs/lang/en/media_videojs.php +++ b/media/player/videojs/lang/en/media_videojs.php @@ -27,19 +27,21 @@ defined('MOODLE_INTERNAL') || die(); $string['audiocssclass'] = 'CSS class for audio'; $string['audioextensions'] = 'Audio file extensions'; $string['configaudiocssclass'] = 'A CSS class that will be added to the <audio> element.'; -$string['configaudioextensions'] = 'A comma-separated list of supported audio file extensions. VideoJS will try to use the browser\'s native video player when available or native VideoJS functionality, and fall back to a Flash player for other formats if Flash is supported by the browser and Flash fallback is enabled below.'; +$string['configaudioextensions'] = 'A comma-separated list of supported audio file extensions. VideoJS will try to use the browser\'s native video player when available or native VideoJS functionality.'; $string['configlimitsize'] = 'If enabled, and width and height are not specified, the video will display with default width and height. Otherwise it will stretch to the maximum possible width.'; -$string['configrtmp'] = 'If enabled, links that start with rtmp:// will be handled by the plugin, irrespective of whether the extension is enabled in the Video file extensions (videoextensions) setting. Flash fallback must be enabled for RTMP to work.'; $string['configvideocssclass'] = 'A CSS class that will be added to the <video> element. For example, the CSS class "vjs-big-play-centered" will place the play button in the middle. For details, including how to set a custom skin, see docs.videojs.com.'; -$string['configvideoextensions'] = 'A comma-separated list of supported video file extensions. VideoJS will try to use the browser\'s native video player when available, and fall back to a Flash player for other formats if Flash is supported by the browser and Flash fallback is enabled below.'; +$string['configvideoextensions'] = 'A comma-separated list of supported video file extensions. VideoJS will try to use the browser\'s native video player when available.'; $string['configyoutube'] = 'Use VideoJS to play YouTube videos. Note that YouTube playlists are not yet supported by VideoJS.'; -$string['configuseflash'] = 'Use Flash player if video format is not natively supported by the browser and/or natively by the VideoJS player. If enabled, VideoJS will be engaged for any file extension from the above list without browser check. Please note that Flash is not available in mobile browsers and discouraged in many desktop ones.'; $string['limitsize'] = 'Limit size'; $string['pluginname'] = 'VideoJS player'; -$string['pluginname_help'] = 'A JavaScript wrapper for video files played by the browser\'s native video player with a Flash player fallback. (Format support depends on the browser.)'; +$string['pluginname_help'] = 'A JavaScript wrapper for video files played by the browser\'s native video player. (Format support depends on the browser.)'; $string['privacy:metadata'] = 'The VideoJS player media plugin does not store any personal data.'; -$string['rtmp'] = 'RTMP streams'; $string['videoextensions'] = 'Video file extensions'; -$string['useflash'] = 'Use Flash fallback'; $string['videocssclass'] = 'CSS class for video'; $string['youtube'] = 'YouTube videos'; + +// Deprecated since Moodle 4.0. +$string['configrtmp'] = 'If enabled, links that start with rtmp:// will be handled by the plugin, irrespective of whether the extension is enabled in the Video file extensions (videoextensions) setting. Flash fallback must be enabled for RTMP to work.'; +$string['configuseflash'] = 'Use Flash player if video format is not natively supported by the browser and/or natively by the VideoJS player. If enabled, VideoJS will be engaged for any file extension from the above list without browser check. Please note that Flash is not available in mobile browsers and discouraged in many desktop ones.'; +$string['rtmp'] = 'RTMP streams'; +$string['useflash'] = 'Use Flash fallback'; diff --git a/media/player/videojs/readme_moodle.txt b/media/player/videojs/readme_moodle.txt index 7c3776ee787..2eb35d59936 100644 --- a/media/player/videojs/readme_moodle.txt +++ b/media/player/videojs/readme_moodle.txt @@ -26,14 +26,3 @@ Import plugins: define(['videojs'] with define(['media_videojs/video-lazy'] - -2. Download the latest release from https://github.com/videojs/videojs-flash - Run "npm install" - Copy 'dist/videojs-flash.js' into 'amd/src/videojs-flash-lazy.js' - In the beginning of the js file replace - define(['videojs'] - with - define(['media_videojs/video-lazy'] - -3. Download https://github.com/videojs/video-js-swf/blob/master/dist/video-js.swf - and place it into 'videojs/video-js.swf' \ No newline at end of file diff --git a/media/player/videojs/settings.php b/media/player/videojs/settings.php index 852ab11fca2..91e45c566df 100644 --- a/media/player/videojs/settings.php +++ b/media/player/videojs/settings.php @@ -38,14 +38,6 @@ if ($ADMIN->fulltree) { 'html_audio', array('onlytypes' => array('audio', 'web_audio', 'html_audio')))); - $settings->add(new admin_setting_configcheckbox('media_videojs/rtmp', - new lang_string('rtmp', 'media_videojs'), - new lang_string('configrtmp', 'media_videojs'), 0)); - - $settings->add(new admin_setting_configcheckbox('media_videojs/useflash', - new lang_string('useflash', 'media_videojs'), - new lang_string('configuseflash', 'media_videojs'), 0)); - $settings->add(new admin_setting_configcheckbox('media_videojs/youtube', new lang_string('youtube', 'media_videojs'), new lang_string('configyoutube', 'media_videojs'), 1)); diff --git a/media/player/videojs/tests/player_test.php b/media/player/videojs/tests/player_test.php index 2defbe0f1a1..893e63b3e43 100644 --- a/media/player/videojs/tests/player_test.php +++ b/media/player/videojs/tests/player_test.php @@ -22,7 +22,12 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); +namespace media_videojs; + +use core_media_manager; +use html_writer; +use media_videojs_plugin; +use moodle_url; /** * Test script for media embedding. @@ -31,7 +36,7 @@ defined('MOODLE_INTERNAL') || die(); * @copyright 2016 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class media_videojs_player_testcase extends advanced_testcase { +class player_test extends \advanced_testcase { /** * Pre-test setup. Preserves $CFG. @@ -46,7 +51,7 @@ class media_videojs_player_testcase extends advanced_testcase { \core\plugininfo\media::set_enabled_plugins('videojs'); // Pretend to be using Firefox browser (must support ogg for tests to work). - core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 '); + \core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 '); } /** @@ -64,8 +69,6 @@ class media_videojs_player_testcase extends advanced_testcase { $supportedextensions = array_merge(file_get_typegroup('extension', 'html_video'), file_get_typegroup('extension', 'html_audio'), file_get_typegroup('extension', 'media_source')); - set_config('useflash', 0, 'media_videojs'); - // Make sure that the list of extensions from the setting is filtered to HTML5 natively supported extensions. $player = new media_videojs_plugin(); $this->assertTrue(in_array('.mp3', $player->get_supported_extensions())); @@ -79,18 +82,11 @@ class media_videojs_player_testcase extends advanced_testcase { $this->assertFalse(in_array('.ra', $player->get_supported_extensions())); $this->assertEmpty(array_diff($player->get_supported_extensions(), $supportedextensions)); - // Try to use flash extensions and make sure they are not returned as supported. + // Check flash extensions are not returned as supported. set_config('videoextensions', '.flv,.f4v', 'media_videojs'); $player = new media_videojs_plugin(); $this->assertFalse(in_array('.flv', $player->get_supported_extensions())); $this->assertFalse(in_array('.f4v', $player->get_supported_extensions())); - - // Enable flash and test if flash extenstions are supported. - set_config('useflash', 1, 'media_videojs'); - set_config('videoextensions', '.flv,.f4v', 'media_videojs'); - $player = new media_videojs_plugin(); - $this->assertTrue(in_array('.flv', $player->get_supported_extensions())); - $this->assertTrue(in_array('.f4v', $player->get_supported_extensions())); } /** @@ -259,7 +255,6 @@ class media_videojs_player_testcase extends advanced_testcase { */ public function test_youtube() { set_config('youtube', 1, 'media_videojs'); - set_config('useflash', 0, 'media_videojs'); $manager = core_media_manager::instance(); @@ -316,7 +311,6 @@ class media_videojs_player_testcase extends advanced_testcase { */ public function test_youtube_start_time(string $url, int $expectedstart) { set_config('youtube', 1, 'media_videojs'); - set_config('useflash', 0, 'media_videojs'); $embedcode = core_media_manager::instance()->embed_url(new moodle_url($url)); @@ -335,23 +329,11 @@ class media_videojs_player_testcase extends advanced_testcase { } /** - * Test that VideoJS can embed flash videos. + * Test that VideoJS can not embed flash videos. */ - public function test_flash() { + public function test_flash_behaviour() { $manager = core_media_manager::instance(); - // Flash enabled. - set_config('useflash', 1, 'media_videojs'); - $url = new moodle_url('http://example.org/some_filename.flv'); - $t = $manager->embed_url($url); - $this->flash_plugin_engaged($t); - $this->assertMatchesRegularExpression('~~', $t); - $this->assertMatchesRegularExpression('~assertMatchesRegularExpression( - '~some_filename.flv~', $t); - - // Flash disabled. - set_config('useflash', 0, 'media_videojs'); $url = new moodle_url('http://example.org/some_filename.flv'); $t = $manager->embed_url($url); $this->assertStringNotContainsString('mediaplugin_videojs', $t); @@ -360,51 +342,15 @@ class media_videojs_player_testcase extends advanced_testcase { } /** - * Test that VideoJS can embed RTMP streams. + * Test that VideoJS can not embed RTMP streams. */ - public function test_rtmp() { + public function test_rtmp_behaviour() { $manager = core_media_manager::instance(); - // RTMP disabled, flash disabled. - set_config('useflash', 0, 'media_videojs'); - set_config('rtmp', 0, 'media_videojs'); $url = new moodle_url('rtmp://example.com/fms&mp4:path/to/file.mp4'); $t = $manager->embed_url($url); $this->assertStringNotContainsString('mediaplugin_videojs', $t); $this->assertMatchesRegularExpression( '~file.mp4~', $t); - - // RTMP enabled, flash disabled. - set_config('useflash', 0, 'media_videojs'); - set_config('rtmp', 1, 'media_videojs'); - $url = new moodle_url('rtmp://example.com/fms&mp4:path/to/file.mp4'); - $t = $manager->embed_url($url); - $this->assertStringNotContainsString('mediaplugin_videojs', $t); - $this->assertMatchesRegularExpression( - '~file.mp4~', $t); - - // RTMP enabled, flash enabled, rtmp/mp4 type expected. - set_config('useflash', 1, 'media_videojs'); - set_config('rtmp', 1, 'media_videojs'); - $url = new moodle_url('rtmp://example.com/fms&mp4:path/to/file.mp4'); - $t = $manager->embed_url($url); - $this->flash_plugin_engaged($t); - $this->assertMatchesRegularExpression('~~', $t); - $this->assertMatchesRegularExpression( - '~assertMatchesRegularExpression( - '~file.mp4~', $t); - - // RTMP enabled, flash enabled, rtmp/flv type expected. - set_config('useflash', 1, 'media_videojs'); - set_config('rtmp', 1, 'media_videojs'); - $url = new moodle_url('rtmp://example.com/fms&flv:path/to/file.flv'); - $t = $manager->embed_url($url); - $this->flash_plugin_engaged($t); - $this->assertMatchesRegularExpression('~~', $t); - $this->assertMatchesRegularExpression( - '~assertMatchesRegularExpression( - '~file.flv~', $t); } } diff --git a/media/player/videojs/thirdpartylibs.xml b/media/player/videojs/thirdpartylibs.xml index 1a9bb61b670..2b0a351ba4f 100644 --- a/media/player/videojs/thirdpartylibs.xml +++ b/media/player/videojs/thirdpartylibs.xml @@ -21,18 +21,4 @@ 7.10.0 2.0 - - amd/src/videojs-flash-lazy.js - The Flash tech for video.js - Apache - 2.2.1 - 2.0 - - - videojs/video-js.swf - Custom Flash Player for VideoJS - Apache - 5.4.2 - 2.0 - diff --git a/media/player/videojs/version.php b/media/player/videojs/version.php index a1f0feed12e..174bd23a6a4 100644 --- a/media/player/videojs/version.php +++ b/media/player/videojs/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2021052502; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2021052503; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2021052500; // Requires this Moodle version. $plugin->component = 'media_videojs'; // Full name of the plugin (used for diagnostics). diff --git a/media/player/videojs/videojs/LICENSE b/media/player/videojs/videojs/LICENSE deleted file mode 100644 index 8a7f05ff3c6..00000000000 --- a/media/player/videojs/videojs/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright Brightcove, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/media/player/videojs/videojs/video-js.swf b/media/player/videojs/videojs/video-js.swf deleted file mode 100644 index 2f41c87f9447225f1827333f9eb23517eb0c3c74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17350 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