summaryrefslogtreecommitdiff
path: root/data/extensions/html5-video-everywhere@lejenome.me
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/html5-video-everywhere@lejenome.me')
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js350
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/defaults/preferences/prefs.js7
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/harness-options.json222
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/install.rdf28
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/locales.json1
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/options.xul42
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/break.js49
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/common.js123
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/dailymotion.js42
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/facebook.js31
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/metacafe.js57
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/vimeo.js98
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube-formats.js33
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube.js200
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/break.js10
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/dailymotion.js10
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/facebook.js8
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/main.js96
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/metacafe.js12
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/vimeo.js12
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/youtube.js21
21 files changed, 1452 insertions, 0 deletions
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js b/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js
new file mode 100644
index 0000000..840103a
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js
@@ -0,0 +1,350 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+
+'use strict';
+
+// IMPORTANT: Avoid adding any initialization tasks here, if you need to do
+// something before add-on is loaded consider addon/runner module instead!
+
+const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
+ results: Cr, manager: Cm } = Components;
+const ioService = Cc['@mozilla.org/network/io-service;1'].
+ getService(Ci.nsIIOService);
+const resourceHandler = ioService.getProtocolHandler('resource').
+ QueryInterface(Ci.nsIResProtocolHandler);
+const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
+const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
+ getService(Ci.mozIJSSubScriptLoader);
+const prefService = Cc['@mozilla.org/preferences-service;1'].
+ getService(Ci.nsIPrefService).
+ QueryInterface(Ci.nsIPrefBranch);
+const appInfo = Cc["@mozilla.org/xre/app-info;1"].
+ getService(Ci.nsIXULAppInfo);
+const vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
+ getService(Ci.nsIVersionComparator);
+
+
+const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
+ 'install', 'uninstall', 'upgrade', 'downgrade' ];
+
+const bind = Function.call.bind(Function.bind);
+
+let loader = null;
+let unload = null;
+let cuddlefishSandbox = null;
+let nukeTimer = null;
+
+let resourceDomains = [];
+function setResourceSubstitution(domain, uri) {
+ resourceDomains.push(domain);
+ resourceHandler.setSubstitution(domain, uri);
+}
+
+// Utility function that synchronously reads local resource from the given
+// `uri` and returns content string.
+function readURI(uri) {
+ let ioservice = Cc['@mozilla.org/network/io-service;1'].
+ getService(Ci.nsIIOService);
+ let channel = ioservice.newChannel(uri, 'UTF-8', null);
+ let stream = channel.open();
+
+ let cstream = Cc['@mozilla.org/intl/converter-input-stream;1'].
+ createInstance(Ci.nsIConverterInputStream);
+ cstream.init(stream, 'UTF-8', 0, 0);
+
+ let str = {};
+ let data = '';
+ let read = 0;
+ do {
+ read = cstream.readString(0xffffffff, str);
+ data += str.value;
+ } while (read != 0);
+
+ cstream.close();
+
+ return data;
+}
+
+// We don't do anything on install & uninstall yet, but in a future
+// we should allow add-ons to cleanup after uninstall.
+function install(data, reason) {}
+function uninstall(data, reason) {}
+
+function startup(data, reasonCode) {
+ try {
+ let reason = REASON[reasonCode];
+ // URI for the root of the XPI file.
+ // 'jar:' URI if the addon is packed, 'file:' URI otherwise.
+ // (Used by l10n module in order to fetch `locale` folder)
+ let rootURI = data.resourceURI.spec;
+
+ // TODO: Maybe we should perform read harness-options.json asynchronously,
+ // since we can't do anything until 'sessionstore-windows-restored' anyway.
+ let options = JSON.parse(readURI(rootURI + './harness-options.json'));
+
+ let id = options.jetpackID;
+ let name = options.name;
+
+ // Clean the metadata
+ options.metadata[name]['permissions'] = options.metadata[name]['permissions'] || {};
+
+ // freeze the permissionss
+ Object.freeze(options.metadata[name]['permissions']);
+ // freeze the metadata
+ Object.freeze(options.metadata[name]);
+
+ // Register a new resource 'domain' for this addon which is mapping to
+ // XPI's `resources` folder.
+ // Generate the domain name by using jetpack ID, which is the extension ID
+ // by stripping common characters that doesn't work as a domain name:
+ let uuidRe =
+ /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
+
+ let domain = id.
+ toLowerCase().
+ replace(/@/g, '-at-').
+ replace(/\./g, '-dot-').
+ replace(uuidRe, '$1');
+
+ let prefixURI = 'resource://' + domain + '/';
+ let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
+ setResourceSubstitution(domain, resourcesURI);
+
+ // Create path to URLs mapping supported by loader.
+ let paths = {
+ // Relative modules resolve to add-on package lib
+ './': prefixURI + name + '/lib/',
+ './tests/': prefixURI + name + '/tests/',
+ '': 'resource://gre/modules/commonjs/'
+ };
+
+ // Maps addon lib and tests ressource folders for each package
+ paths = Object.keys(options.metadata).reduce(function(result, name) {
+ result[name + '/'] = prefixURI + name + '/lib/'
+ result[name + '/tests/'] = prefixURI + name + '/tests/'
+ return result;
+ }, paths);
+
+ // We need to map tests folder when we run sdk tests whose package name
+ // is stripped
+ if (name == 'addon-sdk')
+ paths['tests/'] = prefixURI + name + '/tests/';
+
+ let useBundledSDK = options['force-use-bundled-sdk'];
+ if (!useBundledSDK) {
+ try {
+ useBundledSDK = prefService.getBoolPref("extensions.addon-sdk.useBundledSDK");
+ }
+ catch (e) {
+ // Pref doesn't exist, allow using Firefox shipped SDK
+ }
+ }
+
+ // Starting with Firefox 21.0a1, we start using modules shipped into firefox
+ // Still allow using modules from the xpi if the manifest tell us to do so.
+ // And only try to look for sdk modules in xpi if the xpi actually ship them
+ if (options['is-sdk-bundled'] &&
+ (vc.compare(appInfo.version, '21.0a1') < 0 || useBundledSDK)) {
+ // Maps sdk module folders to their resource folder
+ paths[''] = prefixURI + 'addon-sdk/lib/';
+ // test.js is usually found in root commonjs or SDK_ROOT/lib/ folder,
+ // so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder
+ // until we no longer support SDK modules in XPI:
+ paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js';
+ }
+
+ // Retrieve list of module folder overloads based on preferences in order to
+ // eventually used a local modules instead of files shipped into Firefox.
+ let branch = prefService.getBranch('extensions.modules.' + id + '.path');
+ paths = branch.getChildList('', {}).reduce(function (result, name) {
+ // Allows overloading of any sub folder by replacing . by / in pref name
+ let path = name.substr(1).split('.').join('/');
+ // Only accept overloading folder by ensuring always ending with `/`
+ if (path) path += '/';
+ let fileURI = branch.getCharPref(name);
+
+ // On mobile, file URI has to end with a `/` otherwise, setSubstitution
+ // takes the parent folder instead.
+ if (fileURI[fileURI.length-1] !== '/')
+ fileURI += '/';
+
+ // Maps the given file:// URI to a resource:// in order to avoid various
+ // failure that happens with file:// URI and be close to production env
+ let resourcesURI = ioService.newURI(fileURI, null, null);
+ let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
+ setResourceSubstitution(resName, resourcesURI);
+
+ result[path] = 'resource://' + resName + '/';
+ return result;
+ }, paths);
+
+ // Make version 2 of the manifest
+ let manifest = options.manifest;
+
+ // Import `cuddlefish.js` module using a Sandbox and bootstrap loader.
+ let cuddlefishPath = 'loader/cuddlefish.js';
+ let cuddlefishURI = 'resource://gre/modules/commonjs/sdk/' + cuddlefishPath;
+ if (paths['sdk/']) { // sdk folder has been overloaded
+ // (from pref, or cuddlefish is still in the xpi)
+ cuddlefishURI = paths['sdk/'] + cuddlefishPath;
+ }
+ else if (paths['']) { // root modules folder has been overloaded
+ cuddlefishURI = paths[''] + 'sdk/' + cuddlefishPath;
+ }
+
+ cuddlefishSandbox = loadSandbox(cuddlefishURI);
+ let cuddlefish = cuddlefishSandbox.exports;
+
+ // Normalize `options.mainPath` so that it looks like one that will come
+ // in a new version of linker.
+ let main = options.mainPath;
+
+ unload = cuddlefish.unload;
+ loader = cuddlefish.Loader({
+ paths: paths,
+ // modules manifest.
+ manifest: manifest,
+
+ // Add-on ID used by different APIs as a unique identifier.
+ id: id,
+ // Add-on name.
+ name: name,
+ // Add-on version.
+ version: options.metadata[name].version,
+ // Add-on package descriptor.
+ metadata: options.metadata[name],
+ // Add-on load reason.
+ loadReason: reason,
+
+ prefixURI: prefixURI,
+ // Add-on URI.
+ rootURI: rootURI,
+ // options used by system module.
+ // File to write 'OK' or 'FAIL' (exit code emulation).
+ resultFile: options.resultFile,
+ // Arguments passed as --static-args
+ staticArgs: options.staticArgs,
+ // Add-on preferences branch name
+ preferencesBranch: options.preferencesBranch,
+
+ // Arguments related to test runner.
+ modules: {
+ '@test/options': {
+ allTestModules: options.allTestModules,
+ iterations: options.iterations,
+ filter: options.filter,
+ profileMemory: options.profileMemory,
+ stopOnError: options.stopOnError,
+ verbose: options.verbose,
+ parseable: options.parseable,
+ checkMemory: options.check_memory,
+ }
+ }
+ });
+
+ let module = cuddlefish.Module('sdk/loader/cuddlefish', cuddlefishURI);
+ let require = cuddlefish.Require(loader, module);
+
+ require('sdk/addon/runner').startup(reason, {
+ loader: loader,
+ main: main,
+ prefsURI: rootURI + 'defaults/preferences/prefs.js'
+ });
+ } catch (error) {
+ dump('Bootstrap error: ' +
+ (error.message ? error.message : String(error)) + '\n' +
+ (error.stack || error.fileName + ': ' + error.lineNumber) + '\n');
+ throw error;
+ }
+};
+
+function loadSandbox(uri) {
+ let proto = {
+ sandboxPrototype: {
+ loadSandbox: loadSandbox,
+ ChromeWorker: ChromeWorker
+ }
+ };
+ let sandbox = Cu.Sandbox(systemPrincipal, proto);
+ // Create a fake commonjs environnement just to enable loading loader.js
+ // correctly
+ sandbox.exports = {};
+ sandbox.module = { uri: uri, exports: sandbox.exports };
+ sandbox.require = function (id) {
+ if (id !== "chrome")
+ throw new Error("Bootstrap sandbox `require` method isn't implemented.");
+
+ return Object.freeze({ Cc: Cc, Ci: Ci, Cu: Cu, Cr: Cr, Cm: Cm,
+ CC: bind(CC, Components), components: Components,
+ ChromeWorker: ChromeWorker });
+ };
+ scriptLoader.loadSubScript(uri, sandbox, 'UTF-8');
+ return sandbox;
+}
+
+function unloadSandbox(sandbox) {
+ if ("nukeSandbox" in Cu)
+ Cu.nukeSandbox(sandbox);
+}
+
+function setTimeout(callback, delay) {
+ let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback({ notify: callback }, delay,
+ Ci.nsITimer.TYPE_ONE_SHOT);
+ return timer;
+}
+
+function shutdown(data, reasonCode) {
+ let reason = REASON[reasonCode];
+ if (loader) {
+ unload(loader, reason);
+ unload = null;
+
+ // Don't waste time cleaning up if the application is shutting down
+ if (reason != "shutdown") {
+ // Avoid leaking all modules when something goes wrong with one particular
+ // module. Do not clean it up immediatly in order to allow executing some
+ // actions on addon disabling.
+ // We need to keep a reference to the timer, otherwise it is collected
+ // and won't ever fire.
+ nukeTimer = setTimeout(nukeModules, 1000);
+
+ // Bug 944951 - bootstrap.js must remove the added resource: URIs on unload
+ resourceDomains.forEach(domain => {
+ resourceHandler.setSubstitution(domain, null);
+ })
+ }
+ }
+};
+
+function nukeModules() {
+ nukeTimer = null;
+ // module objects store `exports` which comes from sandboxes
+ // We should avoid keeping link to these object to avoid leaking sandboxes
+ for (let key in loader.modules) {
+ delete loader.modules[key];
+ }
+ // Direct links to sandboxes should be removed too
+ for (let key in loader.sandboxes) {
+ let sandbox = loader.sandboxes[key];
+ delete loader.sandboxes[key];
+ // Bug 775067: From FF17 we can kill all CCW from a given sandbox
+ unloadSandbox(sandbox);
+ }
+ loader = null;
+
+ // both `toolkit/loader` and `system/xul-app` are loaded as JSM's via
+ // `cuddlefish.js`, and needs to be unloaded to avoid memory leaks, when
+ // the addon is unload.
+
+ unloadSandbox(cuddlefishSandbox.loaderSandbox);
+ unloadSandbox(cuddlefishSandbox.xulappSandbox);
+
+ // Bug 764840: We need to unload cuddlefish otherwise it will stay alive
+ // and keep a reference to this compartment.
+ unloadSandbox(cuddlefishSandbox);
+ cuddlefishSandbox = null;
+}
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/defaults/preferences/prefs.js b/data/extensions/html5-video-everywhere@lejenome.me/defaults/preferences/prefs.js
new file mode 100644
index 0000000..e3d6b4d
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/defaults/preferences/prefs.js
@@ -0,0 +1,7 @@
+pref("extensions.html5-video-everywhere@lejenome.me.prefCdc", 0);
+pref("extensions.html5-video-everywhere@lejenome.me.prefQlt", 2);
+pref("extensions.html5-video-everywhere@lejenome.me.autoplay", 2);
+pref("extensions.html5-video-everywhere@lejenome.me.preload", 2);
+pref("extensions.html5-video-everywhere@lejenome.me.volume", 100);
+pref("extensions.html5-video-everywhere@lejenome.me.disableEmbed", false);
+pref("extensions.html5-video-everywhere@lejenome.me.dontPlayNext", false);
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/harness-options.json b/data/extensions/html5-video-everywhere@lejenome.me/harness-options.json
new file mode 100644
index 0000000..fc1992b
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/harness-options.json
@@ -0,0 +1,222 @@
+{
+ "abort_on_missing": false,
+ "check_memory": false,
+ "enable_e10s": false,
+ "is-sdk-bundled": false,
+ "jetpackID": "html5-video-everywhere@lejenome.me",
+ "loader": "addon-sdk/lib/sdk/loader/cuddlefish.js",
+ "main": "main",
+ "mainPath": "html5-video-everywhere/main",
+ "manifest": {
+ "html5-video-everywhere/break": {
+ "docsSHA256": null,
+ "jsSHA256": "44287333a482842991e2acfd6d4446f1f31c8759349eca1ca94d5a21a570f2e1",
+ "moduleName": "break.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/dailymotion": {
+ "docsSHA256": null,
+ "jsSHA256": "e4107011ad40fcd3741b7d4bf3216aa80126490889ca70264eb7a8a93405e72b",
+ "moduleName": "dailymotion.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/facebook": {
+ "docsSHA256": null,
+ "jsSHA256": "ed4075b7c113a2c869cc7aff028973a4e8f3779361d2d1b3a8468d4ec1cdd6f1",
+ "moduleName": "facebook.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/main": {
+ "docsSHA256": "2600330609036287c5d48070ba591543183b0f1619d06d2c61f016088f81d2ec",
+ "jsSHA256": "9b53c709d2869db49baadc00c3a5cb6bef31ccccd9595be4e851a513b5de34e7",
+ "moduleName": "main",
+ "packageName": "html5-video-everywhere",
+ "requirements": {
+ "./break.js": "html5-video-everywhere/break",
+ "./dailymotion.js": "html5-video-everywhere/dailymotion",
+ "./facebook.js": "html5-video-everywhere/facebook",
+ "./metacafe.js": "html5-video-everywhere/metacafe",
+ "./vimeo.js": "html5-video-everywhere/vimeo",
+ "./youtube.js": "html5-video-everywhere/youtube",
+ "chrome": "chrome",
+ "sdk/page-mod": "sdk/page-mod",
+ "sdk/self": "sdk/self",
+ "sdk/simple-prefs": "sdk/simple-prefs",
+ "sdk/system/events": "sdk/system/events",
+ "sdk/util/array": "sdk/util/array",
+ "sdk/window/utils": "sdk/window/utils"
+ },
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/metacafe": {
+ "docsSHA256": null,
+ "jsSHA256": "3c14cc0f0915d2f5966f6592c7ece0afc1229f783b8ae78a14acf2ea8408fcb8",
+ "moduleName": "metacafe.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/vimeo": {
+ "docsSHA256": null,
+ "jsSHA256": "f44444a72857e73b2b1cad2526aad121e5b96da6f6e201760e6cb6f7d19efa59",
+ "moduleName": "vimeo.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ },
+ "html5-video-everywhere/youtube": {
+ "docsSHA256": null,
+ "jsSHA256": "e0446c651e43306ffe9872354463bcbc0380f050088c1ba19ea85bfbb36ba625",
+ "moduleName": "youtube.js",
+ "packageName": "html5-video-everywhere",
+ "requirements": {},
+ "sectionName": "lib"
+ }
+ },
+ "metadata": {
+ "addon-sdk": {
+ "description": "Add-on development made easy.",
+ "keywords": [
+ "javascript",
+ "engine",
+ "addon",
+ "extension",
+ "xulrunner",
+ "firefox",
+ "browser"
+ ],
+ "license": "MPL 2.0",
+ "name": "addon-sdk"
+ },
+ "html5-video-everywhere": {
+ "author": "Moez Bouhlel <bmoez.j@gmail.com> (http://lejenome.github.io/",
+ "description": "Replace video player with Firefox native video player",
+ "homepage": "https://github.com/lejenome/html5-video-everywhere",
+ "license": "MPL 2.0",
+ "main": "main",
+ "name": "html5-video-everywhere",
+ "permissions": {
+ "private-browsing": true
+ },
+ "version": "0.1.1"
+ }
+ },
+ "name": "html5-video-everywhere",
+ "parseable": false,
+ "preferences": [
+ {
+ "name": "prefCdc",
+ "options": [
+ {
+ "label": "WebM",
+ "value": "0"
+ },
+ {
+ "label": "Mp4",
+ "value": "1"
+ }
+ ],
+ "title": "Preferred Codec",
+ "type": "menulist",
+ "value": 0
+ },
+ {
+ "name": "prefQlt",
+ "options": [
+ {
+ "label": "Higher",
+ "value": "0"
+ },
+ {
+ "label": "High",
+ "value": "1"
+ },
+ {
+ "label": "Medium",
+ "value": "2"
+ },
+ {
+ "label": "Low",
+ "value": "3"
+ }
+ ],
+ "title": "Preferred Quality",
+ "type": "menulist",
+ "value": 2
+ },
+ {
+ "description": "Change default behaviour of the video player of the website",
+ "name": "autoplay",
+ "options": [
+ {
+ "label": "Default",
+ "value": "2"
+ },
+ {
+ "label": "Enabled",
+ "value": "1"
+ },
+ {
+ "label": "Disabled",
+ "value": "0"
+ }
+ ],
+ "title": "Auto Play Video",
+ "type": "menulist",
+ "value": 2
+ },
+ {
+ "description": "Change default behaviour of the video player of the website in case it does not auto play the video",
+ "name": "preload",
+ "options": [
+ {
+ "label": "Default",
+ "value": "2"
+ },
+ {
+ "label": "Enabled",
+ "value": "1"
+ },
+ {
+ "label": "Disabled",
+ "value": "0"
+ }
+ ],
+ "title": "Preload Video",
+ "type": "menulist",
+ "value": 2
+ },
+ {
+ "name": "volume",
+ "title": "Volume",
+ "type": "integer",
+ "value": 100
+ },
+ {
+ "description": "Use default youtube video player for embed videos",
+ "hidden": true,
+ "name": "disableEmbed",
+ "title": "Disable for Embed Youtube",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "description": "Do not tell youtube that video reached the end, so it will no play the next Video on playlist mode",
+ "hidden": true,
+ "name": "dontPlayNext",
+ "title": "Do not play next Item",
+ "type": "bool",
+ "value": false
+ }
+ ],
+ "preferencesBranch": "html5-video-everywhere@lejenome.me",
+ "sdkVersion": "1.17",
+ "staticArgs": {},
+ "verbose": false
+} \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/install.rdf b/data/extensions/html5-video-everywhere@lejenome.me/install.rdf
new file mode 100644
index 0000000..24db335
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/install.rdf
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>html5-video-everywhere@lejenome.me</em:id>
+ <em:version>0.1.1</em:version>
+ <em:type>2</em:type>
+ <em:bootstrap>true</em:bootstrap>
+ <em:unpack>false</em:unpack>
+
+ <!-- Firefox -->
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>26.0</em:minVersion>
+ <em:maxVersion>30.0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>HTML5 Video Everywhere!</em:name>
+ <em:description>Replace video player with Firefox native video player</em:description>
+ <em:creator>Moez Bouhlel &lt;bmoez.j@gmail.com&gt; (http://lejenome.github.io/</em:creator>
+ <em:homepageURL>https://github.com/lejenome/html5-video-everywhere</em:homepageURL>
+ <em:optionsType>2</em:optionsType>
+
+ </Description>
+</RDF> \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/locales.json b/data/extensions/html5-video-everywhere@lejenome.me/locales.json
new file mode 100644
index 0000000..303e186
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/locales.json
@@ -0,0 +1 @@
+{"locales": []}
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/options.xul b/data/extensions/html5-video-everywhere@lejenome.me/options.xul
new file mode 100644
index 0000000..e6a70e2
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/options.xul
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting data-jetpack-id="html5-video-everywhere@lejenome.me" pref="extensions.html5-video-everywhere@lejenome.me.prefCdc" pref-name="prefCdc" title="Preferred Codec" type="menulist">
+ <menulist>
+ <menupopup>
+ <menuitem label="WebM" value="0"/>
+ <menuitem label="Mp4" value="1"/>
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting data-jetpack-id="html5-video-everywhere@lejenome.me" pref="extensions.html5-video-everywhere@lejenome.me.prefQlt" pref-name="prefQlt" title="Preferred Quality" type="menulist">
+ <menulist>
+ <menupopup>
+ <menuitem label="Higher" value="0"/>
+ <menuitem label="High" value="1"/>
+ <menuitem label="Medium" value="2"/>
+ <menuitem label="Low" value="3"/>
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting data-jetpack-id="html5-video-everywhere@lejenome.me" pref="extensions.html5-video-everywhere@lejenome.me.autoplay" pref-name="autoplay" title="Auto Play Video" type="menulist">
+ Change default behaviour of the video player of the website
+ <menulist>
+ <menupopup>
+ <menuitem label="Default" value="2"/>
+ <menuitem label="Enabled" value="1"/>
+ <menuitem label="Disabled" value="0"/>
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting data-jetpack-id="html5-video-everywhere@lejenome.me" pref="extensions.html5-video-everywhere@lejenome.me.preload" pref-name="preload" title="Preload Video" type="menulist">
+ Change default behaviour of the video player of the website in case it does not auto play the video
+ <menulist>
+ <menupopup>
+ <menuitem label="Default" value="2"/>
+ <menuitem label="Enabled" value="1"/>
+ <menuitem label="Disabled" value="0"/>
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting data-jetpack-id="html5-video-everywhere@lejenome.me" pref="extensions.html5-video-everywhere@lejenome.me.volume" pref-name="volume" title="Volume" type="integer"/>
+</vbox>
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/break.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/break.js
new file mode 100644
index 0000000..207dc00
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/break.js
@@ -0,0 +1,49 @@
+(function() {
+ "use strict";
+
+ onReady(() => {
+ var url_r = /"uri":\s*"([^"]*)"/;
+ var width_r = /"width":\s*([^\s,]*),/;
+ var height_r = /"height":\s*([^\s,]*),/;
+ var fmts = {};
+ var data = document.head.innerHTML.match(/"media": \[\s[^\]]*\s\],/);
+ if (!data)
+ return;
+ data = data[0].match(/\{[^}]*\}/g);
+ data.forEach(it =>
+ fmts[it.match(width_r)[1] + "x" + it.match(height_r)[1]] = it.match(url_r)[1]
+ );
+ var url = getPreferredFmt(fmts, {
+ "higher/mp4": "1280x720",
+ "high/mp4": "848x480",
+ "medium/mp4": "640x360",
+ "low/mp4": "301x232" // there is 300x220 too which is audio only
+ });
+ if (url === undefined && !(url = fallback()))
+ return;
+ injectPlayer(url);
+ });
+
+ function injectPlayer(url) {
+ var player = createNode("video", {
+ controls: true,
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ src: url
+ }, {
+ width: "100%",
+ heigth: "100%"
+ });
+
+ document.body.innerHTML = "";
+ document.head.innerHTML = "";
+ document.body.appendChild(player);
+ }
+
+ function fallback() {
+ // Just fallback method if the first one didn't work
+ var url_r = /"videoUri":\s*"([^"]*)"/;
+ var url = (document.head.innerHTML.match(url_r) || ["", ""])[1];
+ return url;
+ }
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/common.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/common.js
new file mode 100644
index 0000000..637cc00
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/common.js
@@ -0,0 +1,123 @@
+/* global OPTIONS:true, onPrefChange:true, getPreferredFmt:true */
+/* global createNode:true, asyncGet:true, onReady:true, onInit:true, logify:true */
+/* global preLoad:true, autoPlay:true, HANDLE_VOL_PREF_CHANGE:true */
+// the following jshint global rule is only because jshint support for ES6 arrow
+// functions is limited
+/* global wrapper:true, args:true, auto:true */
+"use strict";
+
+//This Addons Preferences
+var OPTIONS = {};
+// push your prefernces change listner function to this table, yah the old way
+const onPrefChange = [];
+const Qlt = [
+ "higher",
+ "high",
+ "medium",
+ "low"
+];
+// set it to false if the module uses custom listener
+var HANDLE_VOL_PREF_CHANGE = true;
+const Cdc = ["webm", "mp4"];
+self.port.on("preferences", function(prefs) {
+ OPTIONS = prefs;
+ onPrefChange.forEach(f => f());
+});
+
+self.port.on("prefChanged", function(pref) {
+ OPTIONS[pref.name] = pref.value;
+ if (pref.name === "volume" && HANDLE_VOL_PREF_CHANGE === true)
+ Array.forEach(document.getElementsByTagName("video"), el => {
+ el.volume = OPTIONS.volume / 100;
+ });
+ onPrefChange.forEach(f => f(pref.name));
+});
+
+const getPreferredFmt = (fmts, wrapper = {}) => {
+ // for example of the optional wrapper, see data/youtube-formats.js
+ var i, j, slct;
+ var _cdc = [
+ Cdc[OPTIONS.prefCdc],
+ Cdc[(OPTIONS.prefCdc + 1 % 2)]
+ ];
+ i = OPTIONS.prefQlt;
+ while (i > -1) {
+ for (j = 0; j < 2; j++) {
+ slct = Qlt[i] + "/" + _cdc[j];
+ slct = wrapper[slct] || slct;
+ if (fmts[slct])
+ return fmts[slct];
+ }
+ i = (i >= OPTIONS.prefQlt) ? i + 1 : i - 1;
+ if (i > 3)
+ i = OPTIONS.prefQlt - 1;
+ }
+ logify("Error on getPreferredFmt", fmts, wrapper);
+};
+
+const createNode = (type, prprt, style, data) => {
+ logify("createNode", type, prprt);
+ var node = document.createElement(type);
+ if (prprt)
+ Object.keys(prprt).forEach(p => node[p] = prprt[p]);
+ if (style)
+ Object.keys(style).forEach(s => node.style[s] = style[s]);
+ if (data)
+ Object.keys(data).forEach(d => node.dataset[d] = data[d]);
+ return node;
+};
+
+const asyncGet = (url, headers, mimetype) => {
+ logify("asyncGet", url);
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ if (headers)
+ Object.keys(headers).forEach(h => xhr.setRequestHeader(h, headers[h]));
+ if (mimetype && xhr.overrideMimeType)
+ xhr.overrideMimeType(mimetype);
+ xhr.onload = function() {
+ if (this.status !== 200) {
+ reject(this.status);
+ logify("Error on asyncGet", url, headers, this.status);
+ return;
+ }
+ resolve(this.responseText);
+ };
+ xhr.onerror = function() {
+ reject();
+ };
+ xhr.send();
+ });
+};
+
+const logify = (...args) =>
+ console.log.apply(console, args.map(s => JSON.stringify(s, null, 2)));
+
+const onReady = f => {
+ //TODO: document readyState is "loading" (and DOMECotentLoaded) even DOM elements are
+ //accessible
+ try {
+ if (document.readyState !== "loading") {
+ f();
+ } else {
+ document.addEventListener("DOMContentLoaded", f);
+ }
+ } catch (e) {
+ console.error("Exception", e.lineNumber, e.columnNumber, e.message, e.stack);
+ }
+};
+
+const onInit = f => {
+ // code running on when="ready" mode or does not need until onReady
+ // execc but depend on preferences, need to wrapped to this funct.
+ // need
+ document.onafterscriptexecute = function() {
+ document.onafterscriptexecute = undefined;
+ f();
+ };
+};
+const autoPlay = (auto = false) => ((OPTIONS.autoplay === 1 || auto === true) &&
+ OPTIONS.autoplay !== 0);
+const preLoad = (auto = false) => ((OPTIONS.preload === 1 || auto === true) &&
+ OPTIONS.preload !== 0) ? "auto" : "metadata"; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/dailymotion.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/dailymotion.js
new file mode 100644
index 0000000..7732ec4
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/dailymotion.js
@@ -0,0 +1,42 @@
+(function() {
+ "use strict";
+
+ onReady(() => {
+
+ // VIDEO_ID = location.pathname.match(/\/embed\/video\/([^_]+)/)[1];
+ // asyncGet http://www.dailymotion.com/json/video/<VIDEO_ID>?fields=stream_audio_url,stream_h264_hd1080_url,stream_h264_hd_url,stream_h264_hq_url,stream_h264_ld_url,stream_h264_url,stream_hls_url,stream_live_hls_url,thumbnail_120_url,thumbnail_240_url,thumbnail_url
+ // returns a json
+ var streams_r = /"stream_h264[^"]*_url":"[^"]*"/g;
+ var url_r = /"(stream_h264[^"]*_url)":"([^"]*)"/;
+ var streams = document.body.innerHTML.match(streams_r);
+ var url, urls = {};
+ streams.forEach(u => {
+ var r = u.match(url_r);
+ urls[r[1]] = r[2].replace("\\/", "/", "g");
+ });
+ var types = [];
+ url = getPreferredFmt(urls, {
+ // stream_h264_hd1080_url
+ "higher/mp4": "stream_h264_hd_url", // H264 1280x720
+ "high/mp4": "stream_h264_hq_url", // H264 848x480
+ "medium/mp4": "stream_h264_url", // H264 512x384
+ "low/mp4": "stream_h264_ld_url" // H264 320x240
+ });
+ if (url === undefined)
+ return;
+ var poster = (document.body.innerHTML.match(/"thumbnail_url":"([^"]*)"/) || ["", ""])[1].replace("\\/", "/", "g");
+ var player = createNode("video", {
+ controls: true,
+ autoplay: autoPlay(),
+ preload: preLoad(),
+ poster: poster,
+ src: url
+ }, {
+ width: "100%",
+ heigth: "100%"
+ });
+
+ document.body.innerHTML = "";
+ document.body.appendChild(player);
+ });
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/facebook.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/facebook.js
new file mode 100644
index 0000000..136b1b9
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/facebook.js
@@ -0,0 +1,31 @@
+(function() {
+ "use strict";
+ // Facebook module is injected when page is "ready", so onReady() will exec
+ // the code directly, even before addon preferences are fetched. Because
+ // they are needed by the following code, we use onInit() instead of
+ // onReady() so our code get Executed after the prefernces get fetched.
+ // Waw! seems the longest code documentation I ever wrote o.0
+ onInit(() => {
+ var params = document.body.innerHTML.match(/\"params\",(\"[^\"]*\")/)[1];
+ params = JSON.parse(decodeURIComponent(JSON.parse(params)));
+ var url = getPreferredFmt({
+ "medium/mp4": params.video_data[0].sd_src,
+ "high/mp4": params.video_data[0].hd_src
+ });
+ if (url === undefined)
+ return;
+ var player = createNode("video", {
+ // preload: true,
+ controls: true,
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ src: url
+ }, {
+ width: "100%",
+ heigth: "100%"
+ });
+
+ document.getElementsByClassName("_53j5")[0].innerHTML = "";
+ document.getElementsByClassName("_53j5")[0].appendChild(player);
+ });
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/metacafe.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/metacafe.js
new file mode 100644
index 0000000..022d811
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/metacafe.js
@@ -0,0 +1,57 @@
+(function() {
+ "use strict";
+
+ onReady(() => {
+ if (/watch\/\d+\/.*/.test(location.pathname))
+ watchPage();
+ else if (/[^\/]+\/?$/.test(location.pathname))
+ channelPage();
+ });
+
+ function watchPage() {
+ var ob = document.getElementById("flashVars");
+ if (!ob)
+ return;
+ var url = getURL(ob.value);
+ var player = createNode("video", {
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ controls: true,
+ src: url
+ });
+
+ var container = document.getElementById("ItemContainer");
+ if (!container)
+ return;
+ container.innerHTML = "";
+ container.appendChild(player);
+ }
+
+ function channelPage() {
+ var embed = document.getElementsByTagName("embed");
+ if (!embed)
+ return;
+ embed = embed[0];
+ var page = embed.src;
+ page = page.replace("/fplayer/", "/watch/").replace(/.swf$/, "");
+ asyncGet(page).then((data) => {
+ var url = getURL(data);
+ var player = createNode("video", {
+ autoplay: autoPlay(false),
+ preload: preLoad(),
+ controls: true,
+ src: url
+ });
+ var container = embed.parentElement;
+ container.innerHTML = "";
+ container.appendChild(player);
+
+ });
+ }
+
+ function getURL(e) {
+ var data = decodeURIComponent(e.match(/&mediaData=([^&]*)&/)[1]);
+ return JSON.parse(data).MP4.mediaURL;
+ }
+
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/vimeo.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/vimeo.js
new file mode 100644
index 0000000..b3d3e43
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/vimeo.js
@@ -0,0 +1,98 @@
+(function() {
+ "use strict";
+
+ onReady(() =>
+ getConfig().then(getVideoInfo)
+ );
+
+ function injectPlayer(conf) {
+ try {
+ let player_container, player;
+ if (conf.isEmbed) {
+ player_container = document.body;
+ player_container.innerHTML = "";
+ } else if (conf.isWatch) {
+ player_container = document.getElementById("video");
+ player_container.children[1].remove();
+ } else {
+ player_container = document.getElementById("clip_" + conf.id);
+ player_container.innerHTML = "";
+ }
+ if (!player_container)
+ return;
+ player = createNode("video", {
+ className: conf.className,
+ autoplay: autoPlay(),
+ preload: preLoad(),
+ controls: true,
+ poster: conf.poster,
+ volume: OPTIONS.volume / 100
+ });
+ player.appendChild(createNode("source", {
+ src: conf.url
+ }));
+ player_container.appendChild(player);
+ } catch (e) {
+ console.error("Exception on changePlayer()", e.lineNumber, e.columnNumber, e.message, e.stack);
+ }
+ }
+
+ function getConfig() {
+ return new Promise((resolve, reject) => {
+ var isWatch = /https?:\/\/vimeo.com\/[\d]+/.test(location.href);
+ var isEmbed = /https?:\/\/player.vimeo.com\/video/.test(location.href);
+ var isChannel = /https?:\/\/vimeo.com\/(channels\/|)\w+/.test(location.href);
+ if (!isWatch && !isChannel && !isEmbed)
+ reject();
+ var player_id, player_class;
+ if (isWatch) {
+ player_id = location.pathname.match(/^\/([\d]+)/)[1];
+ player_class = "player";
+ } else if (isEmbed) {
+ player_id = location.pathname.match(/video\/([\d]+)/)[1];
+ player_class = "fallback";
+ } else if (isChannel) {
+ player_class = "player";
+ }
+ if (!player_id && !isChannel)
+ reject();
+ resolve({
+ isWatch: isWatch,
+ isEmbed: isEmbed,
+ isChannel: isChannel,
+ id: player_id,
+ className: player_class
+ });
+ });
+ }
+
+ function getVideoInfo(conf) {
+ const processData = (conf) => (data) => {
+ data = JSON.parse(data);
+ var fmt = getPreferredFmt(data.request.files.h264, {
+ "high/mp4": "hd",
+ "medium/mp4": "sd",
+ "low/mp4": "mobile"
+ });
+ if (fmt === undefined)
+ return Promise.reject();
+ conf.poster = data.video.thumbs.base;
+ conf.url = fmt.url;
+ return Promise.resolve(conf);
+ };
+ const INFO_URL = "https://player.vimeo.com/video/";
+ if (conf.isChannel) {
+ return Array.map(document.getElementsByClassName("player_container"), (el) => {
+ var _conf = {};
+ for (var va in conf)
+ _conf[va] = conf[va];
+ _conf.id = el.id.replace("clip_", "");
+ return asyncGet(INFO_URL + _conf.id + "/config").then(processData(_conf))
+ .then(injectPlayer);
+ });
+ } else {
+ return asyncGet(INFO_URL + conf.id + "/config").then(processData(conf))
+ .then(injectPlayer);
+ }
+ }
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube-formats.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube-formats.js
new file mode 100644
index 0000000..e23cf83
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube-formats.js
@@ -0,0 +1,33 @@
+// wrap getPreferedFmt selector to YT itag eq, as we the passed fmts object
+// later has itags as keys not getPreferredFmt known keys
+var FMT_WRAPPER = {
+ "high/mp4": "22",
+ "medium/mp4": "18",
+ "medium/webm": "43"
+};
+/*
++----+-----------+------------+---------+-------------------------------------------
+|FMT | container | resolution | profile | type
++----+-----------+------------+---------+-------------------------------------------
+| 18 | mp4 | 360p | normal | "video/mp4; codecs=\"avc1.42001E, mp4a.40.2\""
+| 22 | mp4 | 720p | normal | "video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""
+| 43 | webm | 360p | normal | "video/webm; codecs=\"vp8.0, vorbis\""
++----+-----------+------------+---------+------------------------------------------
+| 82 | mp4 | 360p | 3D |
+| 83 | mp4 | 240p | 3D |
+| 84 | mp4 | 720p | 3D |
+| 85 | mp4 | 1080p | 3D |
+|100 | webm | 360p | 3D |
+|101 | webm | 360p | 3D |
+|102 | webm | 700p | 3D |
+|133 | mp4 | 240p | DASH V |
+|134 | mp4 | 360p | DASH V |
+|135 | mp4 | 480p | DASH V |
+|136 | mp4 | 720p | DASH V |
+|137 | mp4 | 1080p | DASH V |
+|160 | mp4 | 144p | DASH V |
+|264 | mp4 | 1440p | DASH V |
+|. | . | . | . |
++----+-----------+------------+---------+----------------------------------------
+MORE FROM: http://en.wikipedia.org/wiki/YouTube
+*/ \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube.js
new file mode 100644
index 0000000..431ad9d
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/data/youtube.js
@@ -0,0 +1,200 @@
+/*globals FMT_WRAPPER*/
+(function() {
+ "use strict";
+ var player, player_container;
+
+ onReady(() => {
+ player = createNode("video");
+ changePlayer();
+ window.addEventListener("spfrequest", function() {
+ if (player)
+ player.src = "";
+ });
+ window.addEventListener("spfdone", function() {
+ changePlayer();
+ });
+ });
+
+ function changePlayer() {
+ getConfig()
+ .then(getVideoInfo)
+ .then((conf) => {
+ try {
+ if (player_container)
+ player_container.innerHTML = "";
+ player_container = getPlayerContainer(conf);
+ if (!player_container)
+ return;
+ player_container.innerHTML = "";
+ player_container.className = conf.className || "";
+ player = createNode("video", {
+ id: "video_player",
+ className: conf.className || "",
+ autoplay: autoPlay(!conf.isEmbed),
+ preload: preLoad(),
+ controls: true,
+ poster: conf.poster || "",
+ volume: OPTIONS.volume / 100
+ }, {
+ position: "relative"
+ });
+ player.appendChild(createNode("source", {
+ src: conf.url,
+ type: conf.type
+ }));
+ player_container.appendChild(player);
+ } catch (e) {
+ console.error("Exception on changePlayer()", e.lineNumber, e.columnNumber, e.message, e.stack);
+ }
+ })
+ .catch((rej) => {
+ if (rej === undefined)
+ return;
+ switch (rej.error) {
+ case "VIDEO_URL_UNACCESSIBLE":
+ var error = rej.data.match(/reason=([^&]*)&/);
+ if (error)
+ errorMessage("Failed to load video url with the following error message: " +
+ error[1].replace("+", " ", "g"));
+ break;
+ case "NO_SUPPORTED_VIDEO_FOUND":
+ errorMessage("Failed to find any playable video url." +
+ (rej.unsig ? " All urls are not signed" : ""), rej.conf);
+ break;
+ }
+ });
+ }
+
+ function errorMessage(msg, conf) {
+ logify("errorMessage", msg, conf);
+ var error_container;
+ if (conf)
+ error_container = getPlayerContainer(conf);
+ if (!error_container)
+ error_container = document.getElementById("player-unavailable") || document.getElementById("player");
+ if (!error_container)
+ return;
+ if (conf && conf.isWatch)
+ error_container.className += " player-height player-width";
+ if (conf && conf.isChannel)
+ error_container.className += " html5-main-video";
+ if (conf && conf.isEmbed) {
+ error_container.className += " full-frame";
+ }
+ error_container.style.background = "linear-gradient(to bottom, #383838 0px, #131313 100%) repeat scroll 0% 0% #262626";
+ error_container.innerHTML = "";
+ error_container.appendChild(createNode("p", {
+ textContent: "Ooops! :("
+ }, {
+ padding: "15px",
+ fontSize: "20px"
+ }));
+ error_container.appendChild(createNode("p", {
+ textContent: msg
+ }, {
+ fontSize: "20px"
+ }));
+ }
+
+ function getPlayerContainer(conf) {
+ if (conf.isWatch)
+ return document.getElementById("player-mole-container");
+ if (conf.isEmbed)
+ return document.body;
+ if (conf.isChannel)
+ return document.getElementsByClassName("c4-player-container")[0];
+ }
+
+ function getConfig() {
+ return new Promise((resolve, reject) => {
+ var isEmbed = location.href.search("youtube.com/embed/") > -1;
+ var isWatch = location.href.search("youtube.com/watch?") > -1;
+ var isChannel = location.href.search("youtube.com/channel/") > -1 || location.href.search("youtube.com/user/") > -1;
+ if (!isEmbed && !isWatch && !isChannel)
+ reject();
+ var player_id, player_class;
+ if (isEmbed) {
+ player_id = location.pathname.match(/^\/embed\/([^?#/]*)/)[1];
+ player_class = "full-frame";
+ } else if (isChannel) {
+ var upsell = document.getElementById("upsell-video");
+ if (!upsell)
+ reject();
+ player_id = upsell.dataset["videoId"];
+ player_class = "html5-main-video";
+ } else {
+ player_id = location.search.slice(1).match(/v=([^/?#]*)/)[1];
+ player_class = "player-width player-height";
+ }
+ if (!player_id)
+ reject({
+ error: "PLAYER_ID_NOT_FOUND"
+ });
+ resolve({
+ isEmbed: isEmbed,
+ isWatch: isWatch,
+ isChannel: isChannel,
+ id: player_id,
+ className: player_class
+ });
+ });
+ }
+
+ function getVideoInfo(conf) {
+ var INFO_URL = "https://www.youtube.com/get_video_info?html5=1&hl=en_US&el=detailpage&video_id=";
+ return asyncGet(INFO_URL + conf.id, {}, "text/plain").then((data) => {
+ if (data.endsWith("="))
+ try {
+ data = atob(data);
+ } catch (_) {}
+ if (/status=fail/.test(data)) {
+ return Promise.reject({
+ error: "VIDEO_URL_UNACCESSIBLE",
+ data: data
+ });
+ }
+ // get the poster url
+ var poster = data.match(/iurlhq=([^&]*)/);
+ if (poster)
+ conf.poster = decodeURIComponent(poster[1]);
+ // extract avalable formats to fmts object
+ var info = data.match(/url_encoded_fmt_stream_map=([^&]*)/)[1];
+ info = decodeURIComponent(info);
+ var fmt, fmts = {},
+ unsignedVideos;
+ info.split(",")
+ .map(it1 => {
+ var oo = {};
+ it1.split("&")
+ .map(it2 => it2.split("="))
+ .map(it3 => [it3[0], decodeURIComponent(it3[1])])
+ .forEach(it4 => oo[it4[0]] = it4[1]);
+ return oo;
+ })
+ .filter(it5 => (player.canPlayType(
+ (it5.type = it5.type.replace("+", " ", "g"))
+ ) === "probably"))
+ .filter(it6 => {
+ if (it6.url.search("signature=") > 0)
+ return true;
+ unsignedVideos = true;
+ logify("Url without signature!!", it6.itag);
+ return false;
+ })
+ .forEach(fmt => fmts[fmt.itag] = fmt);
+ // choose best format from fmts onject
+ fmt = getPreferredFmt(fmts, FMT_WRAPPER);
+ if (fmt === undefined) {
+ return Promise.reject({
+ error: "NO_SUPPORTED_VIDEO_FOUND",
+ unsig: unsignedVideos,
+ conf: conf
+ });
+ } else {
+ conf.url = fmt.url;
+ conf.type = fmt.type;
+ return Promise.resolve(conf);
+ }
+ });
+ }
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/break.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/break.js
new file mode 100644
index 0000000..79f1a8b
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/break.js
@@ -0,0 +1,10 @@
+"use strict";
+var match = [/https?:\/\/www.break.com\/embed\/.*/];
+var inject = [
+ "common.js",
+ "break.js"
+];
+var when = "start";
+exports.when = when;
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/dailymotion.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/dailymotion.js
new file mode 100644
index 0000000..e2c5761
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/dailymotion.js
@@ -0,0 +1,10 @@
+"use strict";
+var match = [/https?:\/\/(www.)dailymotion.com\/embed\/video\/.*/];
+var inject = [
+ "common.js",
+ "dailymotion.js"
+];
+var when = "start";
+exports.when = when;
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/facebook.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/facebook.js
new file mode 100644
index 0000000..a229268
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/facebook.js
@@ -0,0 +1,8 @@
+"use strict";
+var match = [/https?:\/\/(www\.|beta\.)?facebook.com\/video.php\?.*/];
+var inject = [
+ "common.js",
+ "facebook.js"
+];
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/main.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/main.js
new file mode 100644
index 0000000..8240ede
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/main.js
@@ -0,0 +1,96 @@
+/* jshint esnext:true, node:true*/
+"use strict";
+const {
+ Cc, Ci, Cr
+} = require("chrome");
+const {
+ add, remove
+} = require("sdk/util/array");
+const data = require("sdk/self").data;
+const pageMod = require("sdk/page-mod");
+const events = require("sdk/system/events");
+const utils = require("sdk/window/utils");
+var prefs = require("sdk/simple-prefs").prefs;
+// list of current workers
+const workers = [];
+const drivers = [
+ require("./youtube.js"),
+ require("./vimeo.js"),
+ require("./dailymotion.js"),
+ require("./break.js"),
+ require("./metacafe.js"),
+ require("./facebook.js")
+];
+
+for (let driver of drivers) {
+ if (driver.match === void(0))
+ continue;
+ pageMod.PageMod({
+ include: driver.match,
+ contentScriptFile: driver.inject.map(i => data.url(i)),
+ contentScriptWhen: driver.when || "ready",
+ onAttach: onWorkerAttach
+ });
+}
+
+function listener(event) {
+ var channel = event.subject.QueryInterface(Ci.nsIHttpChannel);
+ var url = event.subject.URI.spec;
+ for (let driver of drivers) {
+ for (let redirect of(driver.redirect || [])) {
+ if (redirect.src.test(url)) {
+ channel.redirectTo(Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(
+ String.replace(url, redirect.src, redirect.funct),
+ null,
+ null));
+ console.log("Redirect:", url);
+ return;
+ }
+ }
+ for (let block of(driver.block || [])) {
+ if (block.test(url)) {
+ channel.cancel(Cr.NS_BINDING_ABORTED);
+ console.log("Block:", url);
+ return;
+ }
+ }
+ }
+}
+
+//on Addon prefernces change, send the changes to content-script
+require("sdk/simple-prefs").on("", function prefChangeHandler(pref) {
+ if (pref === "volume" && prefs.volume > 100)
+ prefs.volume = 100;
+ else if (pref === "volume" && prefs.volume < 0)
+ prefs.volume = 0;
+ else
+ workersPrefHandler(pref);
+});
+
+function workersPrefHandler(pref) {
+ for (let worker of workers)
+ worker.port.emit("prefChanged", {
+ name: pref,
+ value: prefs[pref]
+ });
+}
+
+function onWorkerAttach(worker) {
+ console.log("onAttach", worker);
+ //send current Addon preferences to content-script
+ let _prefs = {};
+ for (let pref in prefs)
+ _prefs[pref] = prefs[pref];
+ worker.port.emit("preferences", _prefs);
+ add(workers, worker);
+ worker.on("detach", function(e) {
+ remove(workers, this);
+
+ });
+}
+exports.main = function() {
+ events.on("http-on-modify-request", listener);
+};
+exports.onUnload = function(reason) {
+ events.off("http-on-modify-request", listener);
+}; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/metacafe.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/metacafe.js
new file mode 100644
index 0000000..ca6d179
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/metacafe.js
@@ -0,0 +1,12 @@
+"use strict";
+var match = [/https?:\/\/www.metacafe.com\/watch\/.*/,
+ /https?:\/\/www.metacafe.com\/[^\/]+\/?/
+];
+var inject = [
+ "common.js",
+ "metacafe.js"
+];
+var when = "start";
+exports.when = when;
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/vimeo.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/vimeo.js
new file mode 100644
index 0000000..1475d1d
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/vimeo.js
@@ -0,0 +1,12 @@
+"use strict";
+var when = "start";
+var match = [/https?:\/\/vimeo.com\/.+/,
+ /https?:\/\/player.vimeo.com\/video.*/
+];
+var inject = [
+ "common.js",
+ "vimeo.js"
+];
+exports.when = when;
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/youtube.js b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/youtube.js
new file mode 100644
index 0000000..e054233
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/resources/html5-video-everywhere/lib/youtube.js
@@ -0,0 +1,21 @@
+"use strict";
+var YOUTUBE_FLASH_REGEX = /https?:\/\/(www.)?youtube.com\/v\/([^#?\/]*)/;
+var YT_BIN_REGEX = /https:\/\/s.ytimg.com\/yts\/jsbin\/[^\/]*\/base.js/;
+var YT_PLAYER_REGEX = /https?:\/\/s.ytimg.com\/yts\/jsbin\/[^\/]*\/html5player.js/;
+var when = "start";
+var match = ["*.www.youtube.com"];
+var inject = [
+ "common.js",
+ "youtube-formats.js",
+ "youtube.js"
+];
+var redirect = [{
+ src: /https?:\/\/(www.)?youtube.com\/v\/([^#?\/]*)/,
+ funct: (_1, _2, v) => "https://www.youtube.com/embed/" + v
+}];
+var block = [/https?:\/\/s.ytimg.com\/yts\/jsbin\/[^\/]*\/html5player.js/];
+exports.when = when;
+exports.match = match;
+exports.inject = inject;
+exports.redirect = redirect;
+exports.block = block; \ No newline at end of file