summaryrefslogtreecommitdiff
path: root/data/extensions/html5-video-everywhere@lejenome.me/data
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/html5-video-everywhere@lejenome.me/data')
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/break.js47
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/common.js109
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/dailymotion.js47
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/facebook.js27
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/flashgot-YouTubeSwf.js2185
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/metacafe.js71
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/video-player.js387
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/vimeo.js137
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/youtube-formats.js33
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/data/youtube.js330
10 files changed, 3373 insertions, 0 deletions
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/break.js b/data/extensions/html5-video-everywhere@lejenome.me/data/break.js
new file mode 100644
index 0000000..24fbcb8
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/break.js
@@ -0,0 +1,47 @@
+(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]
+ );
+ injectPlayer(fmts);
+ });
+
+ function injectPlayer(fmts) {
+ rmChildren(document.head);
+ var vp = new VP(document.body);
+ vp.srcs(fmts, {
+ "higher/mp4": "1280x720",
+ "high/mp4": "848x480",
+ "medium/mp4": "640x360",
+ "low/mp4": "301x232" // there is 300x220 too which is audio only
+ });
+ vp.props({
+ controls: true,
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ loop: isLoop()
+ });
+ vp.style({
+ width: "100%",
+ height: "100%"
+ });
+ vp.setup();
+ }
+
+ 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/data/common.js b/data/extensions/html5-video-everywhere@lejenome.me/data/common.js
new file mode 100644
index 0000000..4686831
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/common.js
@@ -0,0 +1,109 @@
+/* global OPTIONS:true, onPrefChange:true, LANGS:true */
+/* global createNode:true, asyncGet:true, onReady:true, logify:true */
+/* global preLoad:true, autoPlay:true, HANDLE_VOL_PREF_CHANGE:true */
+/* global rmChildren:true, Qlt:true, Cdc:true, chgPref:true, isLoop:true */
+/* global setClipboard:true */
+// the following jshint global rule is only because jshint support for ES6 arrow
+// functions is limited
+/* global wrapper:true, args:true, auto:true, lp:true */
+"use strict";
+
+//This Addons Preferences
+var OPTIONS, init;
+// push your prefernces change listner function to this table, yah the old way
+const onPrefChange = [];
+const Cdc = ["webm", "mp4"];
+const Qlt = ["higher", "high", "medium", "low"];
+const LANGS = ["af", "ar", "bn", "de", "en", "es", "fi", "fr", "hi", "id", "is", "it", "ja", "ko", "pt", "ru", "tu", "zh"];
+// set it to false if the module uses custom listener
+var HANDLE_VOL_PREF_CHANGE = true;
+self.port.on("preferences", function(prefs) {
+ OPTIONS = prefs;
+ if (init)
+ init();
+ 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 chgPref = (name, val) => {
+ self.port.emit("prefChang", {
+ name: name,
+ val: val
+ });
+};
+const setClipboard = (text) =>
+ self.port.emit("setClipboard", text);
+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) => {
+ args = args.map(s => JSON.stringify(s, null, 2));
+ args.unshift("[DRIVER]");
+ dump(args.join(" ") + "\n");
+};
+
+const onReady = f => {
+ if (document.readyState !== "loading") {
+ if (OPTIONS)
+ f();
+ else
+ init = f;
+ } else {
+ document.addEventListener("DOMContentLoaded", () => {
+ if (OPTIONS)
+ f();
+ else
+ init = 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";
+const isLoop = (lp = false) => ((OPTIONS.loop === 1 || lp) && OPTIONS.loop !== 0);
+
+const rmChildren = (prnt) => {
+ while (prnt && prnt.firstChild)
+ prnt.removeChild(prnt.firstChild);
+}; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/dailymotion.js b/data/extensions/html5-video-everywhere@lejenome.me/data/dailymotion.js
new file mode 100644
index 0000000..610ca9a
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/dailymotion.js
@@ -0,0 +1,47 @@
+(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 urls = {},
+ poster;
+ if (unsafeWindow.info) {
+ urls = unsafeWindow.info;
+ poster = unsafeWindow.info.thumbnail_url ||
+ unsafeWindow.info.thumbnail_240_url ||
+ unsafeWindow.info.thumbnail_120_url;
+ } else {
+ var streams_r = /"stream_h264[^"]*_url":"[^"]*"/g;
+ var url_r = /"(stream_h264[^"]*_url)":"([^"]*)"/;
+ var streams = document.body.innerHTML.match(streams_r);
+ streams.forEach(u => {
+ var r = u.match(url_r);
+ urls[r[1]] = r[2].replace("\\/", "/", "g");
+ });
+ poster = (document.body.innerHTML.match(/"thumbnail_url":"([^"]*)"/) || ["", ""])[1].replace("\\/", "/", "g");
+ }
+ var vp = new VP(document.body);
+ vp.srcs(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
+ });
+ vp.props({
+ controls: true,
+ autoplay: autoPlay(),
+ preload: preLoad(),
+ loop: isLoop(),
+ poster: poster
+ });
+ vp.style({
+ width: "100%",
+ height: "100%"
+ });
+ vp.setup();
+ });
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/facebook.js b/data/extensions/html5-video-everywhere@lejenome.me/data/facebook.js
new file mode 100644
index 0000000..051d32a
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/facebook.js
@@ -0,0 +1,27 @@
+(function() {
+ "use strict";
+ onReady(() => {
+ var params = document.body.innerHTML.match(/"params",("[^"]*")/)[1];
+ params = JSON.parse(decodeURIComponent(JSON.parse(params)));
+ // var container = document.getElementsByClassName("_53j5")[0];
+ var container = document.getElementsByClassName("stageContainer")[0];
+ var vp = new VP(container);
+ logify(params.video_data[0]);
+ vp.srcs({
+ "medium/mp4": params.video_data[0].sd_src,
+ "high/mp4": params.video_data[0].hd_src
+ });
+ vp.props({
+ controls: true,
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ loop: isLoop()
+ });
+ vp.style({
+ width: "100%",
+ heigth: "100%"
+ });
+ vp.setup();
+
+ });
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/flashgot-YouTubeSwf.js b/data/extensions/html5-video-everywhere@lejenome.me/data/flashgot-YouTubeSwf.js
new file mode 100644
index 0000000..8f36a47
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/flashgot-YouTubeSwf.js
@@ -0,0 +1,2185 @@
+/***** BEGIN LICENSE BLOCK *****
+
+ FlashGot - a Firefox extension for external download managers integration
+ Copyright (C) 2004-2013 Giorgio Maone - g.maone@informaction.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+***** END LICENSE BLOCK *****/
+/* the following jshint rules are added by Moez Bouhlel to pass
+ * HTML5-Video-EveryWhere build validation */
+/* jshint -W033, -W055, -W116, -W016, -W073, -W040, -W071, -W074, -W032, -W004, -W027, -W035, -W052, -W062, -W059, -W084*/
+/* jshint strict:false */
+/* global onmessage:true, postMessage */
+onmessage = function(evt) {
+ try {
+ var rc = refresh_signature_func(evt.data);
+ postMessage({
+ type: "result",
+ data: rc
+ });
+ }
+ // Log errors here because the stacktrace is lost
+ // when they're marshalled to the onerror handler.
+ catch (x) {
+ log("YoutubeSwf: exception: " + (x.message || x) + "\n" + (x.stack || new Error().stack));
+ } finally {
+ // Notify the caller we're done. They will terminate us.
+ postMessage({
+ type: "done"
+ });
+ }
+}
+
+function log(msg) {
+ postMessage({
+ type: "log",
+ data: String(msg)
+ });
+}
+
+
+
+var zip_inflate = function() {
+ // http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
+ /* Copyright (C) 1999,2012 Masanao Izumo <iz@onicos.co.jp>
+ * Version: 1.0.1
+ * LastModified: Jun 29 2012
+ */
+
+ /* Interface:
+ * data = zip_inflate(src);
+ */
+
+ /* constant parameters */
+ var zip_WSIZE = 32768; // Sliding Window size
+ var zip_STORED_BLOCK = 0;
+ var zip_STATIC_TREES = 1;
+ var zip_DYN_TREES = 2;
+
+ /* for inflate */
+ var zip_lbits = 9; // bits in base literal/length lookup table
+ var zip_dbits = 6; // bits in base distance lookup table
+ var zip_INBUFSIZ = 32768; // Input buffer size
+ var zip_INBUF_EXTRA = 64; // Extra buffer
+
+ /* variables (inflate) */
+ var zip_slide;
+ var zip_wp; // current position in slide
+ var zip_fixed_tl = null; // inflate static
+ var zip_fixed_td; // inflate static
+ var zip_fixed_bl, zip_fixed_bd; // inflate static
+ var zip_bit_buf; // bit buffer
+ var zip_bit_len; // bits in bit buffer
+ var zip_method;
+ var zip_eof;
+ var zip_copy_leng;
+ var zip_copy_dist;
+ var zip_tl, zip_td; // literal/length and distance decoder tables
+ var zip_bl, zip_bd; // number of bits decoded by tl and td
+
+ var zip_inflate_data;
+ var zip_inflate_pos;
+
+
+ /* constant tables (inflate) */
+ var zip_MASK_BITS = new Array(
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff);
+ // Tables for deflate from PKZIP's appnote.txt.
+ var zip_cplens = new Array( // Copy lengths for literal codes 257..285
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
+ /* note: see note #13 above about the 258 in this list. */
+ var zip_cplext = new Array( // Extra bits for literal codes 257..285
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99); // 99==invalid
+ var zip_cpdist = new Array( // Copy offsets for distance codes 0..29
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577);
+ var zip_cpdext = new Array( // Extra bits for distance codes
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13);
+ var zip_border = new Array( // Order of the bit length code lengths
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
+ /* objects (inflate) */
+
+ function zip_HuftList() {
+ this.next = null;
+ this.list = null;
+ }
+
+ function zip_HuftNode() {
+ this.e = 0; // number of extra bits or operation
+ this.b = 0; // number of bits in this code or subcode
+
+ // union
+ this.n = 0; // literal, length base, or distance base
+ this.t = null; // (zip_HuftNode) pointer to next level of table
+ }
+
+ function zip_HuftBuild(b, // code lengths in bits (all assumed <= BMAX)
+ n, // number of codes (assumed <= N_MAX)
+ s, // number of simple-valued codes (0..s-1)
+ d, // list of base values for non-simple codes
+ e, // list of extra bits for non-simple codes
+ mm // maximum lookup bits
+ ) {
+ this.BMAX = 16; // maximum bit length of any code
+ this.N_MAX = 288; // maximum number of codes in any set
+ this.status = 0; // 0: success, 1: incomplete table, 2: bad input
+ this.root = null; // (zip_HuftList) starting table
+ this.m = 0; // maximum lookup bits, returns actual
+
+ /* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory.
+ The code with value 256 is special, and the tables are constructed
+ so that no bits beyond that code are fetched when that code is
+ decoded. */
+ {
+ var a; // counter for codes of length k
+ var c = new Array(this.BMAX + 1); // bit length count table
+ var el; // length of EOB code (value 256)
+ var f; // i repeats in table every f entries
+ var g; // maximum code length
+ var h; // table level
+ var i; // counter, current code
+ var j; // counter
+ var k; // number of bits in current code
+ var lx = new Array(this.BMAX + 1); // stack of bits per table
+ var p; // pointer into c[], b[], or v[]
+ var pidx; // index of p
+ var q; // (zip_HuftNode) points to current table
+ var r = new zip_HuftNode(); // table entry for structure assignment
+ var u = new Array(this.BMAX); // zip_HuftNode[BMAX][] table stack
+ var v = new Array(this.N_MAX); // values in order of bit length
+ var w;
+ var x = new Array(this.BMAX + 1); // bit offsets, then code stack
+ var xp; // pointer into x or c
+ var y; // number of dummy codes added
+ var z; // number of entries in current table
+ var o;
+ var tail; // (zip_HuftList)
+
+ tail = this.root = null;
+ for (i = 0; i < c.length; i++)
+ c[i] = 0;
+ for (i = 0; i < lx.length; i++)
+ lx[i] = 0;
+ for (i = 0; i < u.length; i++)
+ u[i] = null;
+ for (i = 0; i < v.length; i++)
+ v[i] = 0;
+ for (i = 0; i < x.length; i++)
+ x[i] = 0;
+
+ // Generate counts for each bit length
+ el = n > 256 ? b[256] : this.BMAX; // set length of EOB code, if any
+ p = b;
+ pidx = 0;
+ i = n;
+ do {
+ c[p[pidx]] ++; // assume all entries <= BMAX
+ pidx++;
+ } while (--i > 0);
+ if (c[0] == n) { // null input--all zero length codes
+ this.root = null;
+ this.m = 0;
+ this.status = 0;
+ return;
+ }
+
+ // Find minimum and maximum length, bound *m by those
+ for (j = 1; j <= this.BMAX; j++)
+ if (c[j] != 0)
+ break;
+ k = j; // minimum code length
+ if (mm < j)
+ mm = j;
+ for (i = this.BMAX; i != 0; i--)
+ if (c[i] != 0)
+ break;
+ g = i; // maximum code length
+ if (mm > i)
+ mm = i;
+
+ // Adjust last length count to fill out codes, if needed
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0) {
+ this.status = 2; // bad input: more codes than bits
+ this.m = mm;
+ return;
+ }
+ if ((y -= c[i]) < 0) {
+ this.status = 2;
+ this.m = mm;
+ return;
+ }
+ c[i] += y;
+
+ // Generate starting offsets into the value table for each length
+ x[1] = j = 0;
+ p = c;
+ pidx = 1;
+ xp = 2;
+ while (--i > 0) // note that i == g from above
+ x[xp++] = (j += p[pidx++]);
+
+ // Make a table of values in order of bit lengths
+ p = b;
+ pidx = 0;
+ i = 0;
+ do {
+ if ((j = p[pidx++]) != 0)
+ v[x[j] ++] = i;
+ } while (++i < n);
+ n = x[g]; // set n to length of v
+
+ // Generate the Huffman codes and for each, make the table entries
+ x[0] = i = 0; // first Huffman code is zero
+ p = v;
+ pidx = 0; // grab values in bit order
+ h = -1; // no tables yet--level -1
+ w = lx[0] = 0; // no bits decoded yet
+ q = null; // ditto
+ z = 0; // ditto
+
+ // go through the bit lengths (k already is bits in shortest code)
+ for (; k <= g; k++) {
+ a = c[k];
+ while (a-- > 0) {
+ // here i is the Huffman code of length k bits for value p[pidx]
+ // make tables up to required level
+ while (k > w + lx[1 + h]) {
+ w += lx[1 + h]; // add bits already decoded
+ h++;
+
+ // compute minimum size table less than or equal to *m bits
+ z = (z = g - w) > mm ? mm : z; // upper limit
+ if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
+ // too few codes for k-w bit table
+ f -= a + 1; // deduct codes from patterns left
+ xp = k;
+ while (++j < z) { // try smaller tables up to z bits
+ if ((f <<= 1) <= c[++xp])
+ break; // enough codes to use up j bits
+ f -= c[xp]; // else deduct codes from patterns
+ }
+ }
+ if (w + j > el && w < el)
+ j = el - w; // make EOB code end at table
+ z = 1 << j; // table entries for j-bit table
+ lx[1 + h] = j; // set table size in stack
+
+ // allocate and link in new table
+ q = new Array(z);
+ for (o = 0; o < z; o++) {
+ q[o] = new zip_HuftNode();
+ }
+
+ if (tail == null)
+ tail = this.root = new zip_HuftList();
+ else
+ tail = tail.next = new zip_HuftList();
+ tail.next = null;
+ tail.list = q;
+ u[h] = q; // table starts after link
+
+ /* connect to last table, if there is one */
+ if (h > 0) {
+ x[h] = i; // save pattern for backing up
+ r.b = lx[h]; // bits to dump before this table
+ r.e = 16 + j; // bits in this table
+ r.t = q; // pointer to this table
+ j = (i & ((1 << w) - 1)) >> (w - lx[h]);
+ u[h - 1][j].e = r.e;
+ u[h - 1][j].b = r.b;
+ u[h - 1][j].n = r.n;
+ u[h - 1][j].t = r.t;
+ }
+ }
+
+ // set up table entry in r
+ r.b = k - w;
+ if (pidx >= n)
+ r.e = 99; // out of values--invalid code
+ else if (p[pidx] < s) {
+ r.e = (p[pidx] < 256 ? 16 : 15); // 256 is end-of-block code
+ r.n = p[pidx++]; // simple code is just the value
+ } else {
+ r.e = e[p[pidx] - s]; // non-simple--look up in lists
+ r.n = d[p[pidx++] - s];
+ }
+
+ // fill code-like entries with r //
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f) {
+ q[j].e = r.e;
+ q[j].b = r.b;
+ q[j].n = r.n;
+ q[j].t = r.t;
+ }
+
+ // backwards increment the k-bit code i
+ for (j = 1 << (k - 1);
+ (i & j) != 0; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ // backup over finished tables
+ while ((i & ((1 << w) - 1)) != x[h]) {
+ w -= lx[h]; // don't need to update q
+ h--;
+ }
+ }
+ }
+
+ /* return actual size of base table */
+ this.m = lx[1];
+
+ /* Return true (1) if we were given an incomplete table */
+ this.status = ((y != 0 && g != 1) ? 1 : 0);
+ } /* end of constructor */
+ }
+
+
+ /* routines (inflate) */
+
+ function zip_GET_BYTE() {
+ if (zip_inflate_data.length == zip_inflate_pos) {
+ throw new Error("EOF");
+ return -1;
+ }
+ return zip_inflate_data.charCodeAt(zip_inflate_pos++) & 0xff;
+ }
+
+ function zip_NEEDBITS(n) {
+ while (zip_bit_len < n) {
+ zip_bit_buf |= zip_GET_BYTE() << zip_bit_len;
+ zip_bit_len += 8;
+ }
+ }
+
+ function zip_GETBITS(n) {
+ return zip_bit_buf & zip_MASK_BITS[n];
+ }
+
+ function zip_DUMPBITS(n) {
+ zip_bit_buf >>= n;
+ zip_bit_len -= n;
+ }
+
+ function zip_inflate_codes(buff, off, size) {
+ /* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+ var e; // table entry flag/number of extra bits
+ var t; // (zip_HuftNode) pointer to table entry
+ var n;
+
+ if (size == 0)
+ return 0;
+
+ // inflate the coded data
+ n = 0;
+ for (;;) { // do until end of block
+ zip_NEEDBITS(zip_bl);
+ t = zip_tl.list[zip_GETBITS(zip_bl)];
+ e = t.e;
+ while (e > 16) {
+ if (e == 99)
+ return -1;
+ zip_DUMPBITS(t.b);
+ e -= 16;
+ zip_NEEDBITS(e);
+ t = t.t[zip_GETBITS(e)];
+ e = t.e;
+ }
+ zip_DUMPBITS(t.b);
+
+ if (e == 16) { // then it's a literal
+ zip_wp &= zip_WSIZE - 1;
+ buff[off + n++] = zip_slide[zip_wp++] = t.n;
+ if (n == size)
+ return size;
+ continue;
+ }
+
+ // exit if end of block
+ if (e == 15)
+ break;
+
+ // it's an EOB or a length
+
+ // get length of block to copy
+ zip_NEEDBITS(e);
+ zip_copy_leng = t.n + zip_GETBITS(e);
+ zip_DUMPBITS(e);
+
+ // decode distance of block to copy
+ zip_NEEDBITS(zip_bd);
+ t = zip_td.list[zip_GETBITS(zip_bd)];
+ e = t.e;
+
+ while (e > 16) {
+ if (e == 99)
+ return -1;
+ zip_DUMPBITS(t.b);
+ e -= 16;
+ zip_NEEDBITS(e);
+ t = t.t[zip_GETBITS(e)];
+ e = t.e;
+ }
+ zip_DUMPBITS(t.b);
+ zip_NEEDBITS(e);
+ zip_copy_dist = zip_wp - t.n - zip_GETBITS(e);
+ zip_DUMPBITS(e);
+
+ // do the copy
+ while (zip_copy_leng > 0 && n < size) {
+ zip_copy_leng--;
+ zip_copy_dist &= zip_WSIZE - 1;
+ zip_wp &= zip_WSIZE - 1;
+ buff[off + n++] = zip_slide[zip_wp++] = zip_slide[zip_copy_dist++];
+ }
+
+ if (n == size)
+ return size;
+ }
+
+ zip_method = -1; // done
+ return n;
+ }
+
+ function zip_inflate_stored(buff, off, size) {
+ /* "decompress" an inflated type 0 (stored) block. */
+ var n;
+
+ // go to byte boundary
+ n = zip_bit_len & 7;
+ zip_DUMPBITS(n);
+
+ // get the length and its complement
+ zip_NEEDBITS(16);
+ n = zip_GETBITS(16);
+ zip_DUMPBITS(16);
+ zip_NEEDBITS(16);
+ if (n != ((~zip_bit_buf) & 0xffff)) {
+ throw new Error("n != (~zip_bit_buf) & 0xffff");
+ return -1; // error in compressed data
+ }
+ zip_DUMPBITS(16);
+
+ // read and output the compressed data
+ zip_copy_leng = n;
+
+ n = 0;
+ while (zip_copy_leng > 0 && n < size) {
+ zip_copy_leng--;
+ zip_wp &= zip_WSIZE - 1;
+ zip_NEEDBITS(8);
+ buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
+ zip_DUMPBITS(8);
+ }
+
+ if (zip_copy_leng == 0)
+ zip_method = -1; // done
+ return n;
+ }
+
+ function zip_inflate_fixed(buff, off, size) {
+ /* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+
+ // if first time, set up tables for fixed blocks
+ if (zip_fixed_tl == null) {
+ var i; // temporary variable
+ var l = new Array(288); // length list for huft_build
+ var h; // zip_HuftBuild
+
+ // literal table
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) // make a complete, but wrong code set
+ l[i] = 8;
+ zip_fixed_bl = 7;
+
+ h = new zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext,
+ zip_fixed_bl);
+ if (h.status != 0) {
+ throw new Error("HufBuild error: " + h.status);
+ return -1;
+ }
+ zip_fixed_tl = h.root;
+ zip_fixed_bl = h.m;
+
+ // distance table
+ for (i = 0; i < 30; i++) // make an incomplete code set
+ l[i] = 5;
+ zip_fixed_bd = 5;
+
+ h = new zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd);
+ if (h.status > 1) {
+ zip_fixed_tl = null;
+ throw new Error("HufBuild error: " + h.status);
+ return -1;
+ }
+ zip_fixed_td = h.root;
+ zip_fixed_bd = h.m;
+ }
+
+ zip_tl = zip_fixed_tl;
+ zip_td = zip_fixed_td;
+ zip_bl = zip_fixed_bl;
+ zip_bd = zip_fixed_bd;
+ return zip_inflate_codes(buff, off, size);
+ }
+
+ function zip_inflate_dynamic(buff, off, size) {
+ // decompress an inflated type 2 (dynamic Huffman codes) block.
+ var i; // temporary variables
+ var j;
+ var l; // last length
+ var n; // number of lengths to get
+ var t; // (zip_HuftNode) literal/length code table
+ var nb; // number of bit length codes
+ var nl; // number of literal/length codes
+ var nd; // number of distance codes
+ var ll = new Array(286 + 30); // literal/length and distance code lengths
+ var h; // (zip_HuftBuild)
+
+ for (i = 0; i < ll.length; i++)
+ ll[i] = 0;
+
+ // read in table lengths
+ zip_NEEDBITS(5);
+ nl = 257 + zip_GETBITS(5); // number of literal/length codes
+ zip_DUMPBITS(5);
+ zip_NEEDBITS(5);
+ nd = 1 + zip_GETBITS(5); // number of distance codes
+ zip_DUMPBITS(5);
+ zip_NEEDBITS(4);
+ nb = 4 + zip_GETBITS(4); // number of bit length codes
+ zip_DUMPBITS(4);
+ if (nl > 286 || nd > 30)
+ return -1; // bad lengths
+
+ // read in bit-length-code lengths
+ for (j = 0; j < nb; j++) {
+ zip_NEEDBITS(3);
+ ll[zip_border[j]] = zip_GETBITS(3);
+ zip_DUMPBITS(3);
+ }
+ for (; j < 19; j++)
+ ll[zip_border[j]] = 0;
+
+ // build decoding table for trees--single level, 7 bit lookup
+ zip_bl = 7;
+ h = new zip_HuftBuild(ll, 19, 19, null, null, zip_bl);
+ if (h.status != 0)
+ return -1; // incomplete code set
+
+ zip_tl = h.root;
+ zip_bl = h.m;
+
+ // read in literal and distance code lengths
+ n = nl + nd;
+ i = l = 0;
+ while (i < n) {
+ zip_NEEDBITS(zip_bl);
+ t = zip_tl.list[zip_GETBITS(zip_bl)];
+ j = t.b;
+ zip_DUMPBITS(j);
+ j = t.n;
+ if (j < 16) // length of code in bits (0..15)
+ ll[i++] = l = j; // save last length in l
+ else if (j == 16) { // repeat last length 3 to 6 times
+ zip_NEEDBITS(2);
+ j = 3 + zip_GETBITS(2);
+ zip_DUMPBITS(2);
+ if (i + j > n)
+ return -1;
+ while (j-- > 0)
+ ll[i++] = l;
+ } else if (j == 17) { // 3 to 10 zero length codes
+ zip_NEEDBITS(3);
+ j = 3 + zip_GETBITS(3);
+ zip_DUMPBITS(3);
+ if (i + j > n)
+ return -1;
+ while (j-- > 0)
+ ll[i++] = 0;
+ l = 0;
+ } else { // j == 18: 11 to 138 zero length codes
+ zip_NEEDBITS(7);
+ j = 11 + zip_GETBITS(7);
+ zip_DUMPBITS(7);
+ if (i + j > n)
+ return -1;
+ while (j-- > 0)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ // build the decoding tables for literal/length and distance codes
+ zip_bl = zip_lbits;
+ h = new zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl);
+ if (zip_bl == 0) // no literals or lengths
+ h.status = 1;
+ if (h.status != 0) {
+ if (h.status == 1)
+ ; // **incomplete literal tree**
+ return -1; // incomplete code set
+ }
+ zip_tl = h.root;
+ zip_bl = h.m;
+
+ for (i = 0; i < nd; i++)
+ ll[i] = ll[i + nl];
+ zip_bd = zip_dbits;
+ h = new zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd);
+ zip_td = h.root;
+ zip_bd = h.m;
+
+ if (zip_bd == 0 && nl > 257) { // lengths but no distances
+ // **incomplete distance tree**
+ return -1;
+ }
+
+ if (h.status == 1) {; // **incomplete distance tree**
+ }
+ if (h.status != 0)
+ return -1;
+
+ // decompress until an end-of-block code
+ return zip_inflate_codes(buff, off, size);
+ }
+
+ function zip_inflate_start() {
+ var i;
+
+ if (zip_slide == null)
+ zip_slide = new Array(2 * zip_WSIZE);
+ zip_wp = 0;
+ zip_bit_buf = 0;
+ zip_bit_len = 0;
+ zip_method = -1;
+ zip_eof = false;
+ zip_copy_leng = zip_copy_dist = 0;
+ zip_tl = null;
+ }
+
+ function zip_inflate_internal(buff, off, size) {
+ // decompress an inflated entry
+ var n, i;
+
+ n = 0;
+ while (n < size) {
+ if (zip_eof && zip_method == -1) {
+ return n;
+ }
+
+ if (zip_copy_leng > 0) {
+ if (zip_method != zip_STORED_BLOCK) {
+ // STATIC_TREES or DYN_TREES
+ while (zip_copy_leng > 0 && n < size) {
+ zip_copy_leng--;
+ zip_copy_dist &= zip_WSIZE - 1;
+ zip_wp &= zip_WSIZE - 1;
+ buff[off + n++] = zip_slide[zip_wp++] =
+ zip_slide[zip_copy_dist++];
+ }
+ } else {
+ while (zip_copy_leng > 0 && n < size) {
+ zip_copy_leng--;
+ zip_wp &= zip_WSIZE - 1;
+ zip_NEEDBITS(8);
+ buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
+ zip_DUMPBITS(8);
+ }
+ if (zip_copy_leng == 0)
+ zip_method = -1; // done
+ }
+ if (n == size) {
+ return n;
+ }
+ }
+
+ if (zip_method == -1) {
+ if (zip_eof) {
+ break;
+ }
+
+ // read in last block bit
+ zip_NEEDBITS(1);
+ if (zip_GETBITS(1) != 0)
+ zip_eof = true;
+ zip_DUMPBITS(1);
+
+ // read in block type
+ zip_NEEDBITS(2);
+ zip_method = zip_GETBITS(2);
+ zip_DUMPBITS(2);
+ zip_tl = null;
+ zip_copy_leng = 0;
+ }
+
+ switch (zip_method) {
+ case 0: // zip_STORED_BLOCK
+ i = zip_inflate_stored(buff, off + n, size - n);
+ break;
+
+ case 1: // zip_STATIC_TREES
+ if (zip_tl != null)
+ i = zip_inflate_codes(buff, off + n, size - n);
+ else
+ i = zip_inflate_fixed(buff, off + n, size - n);
+ break;
+
+ case 2: // zip_DYN_TREES
+ if (zip_tl != null)
+ i = zip_inflate_codes(buff, off + n, size - n);
+ else
+ i = zip_inflate_dynamic(buff, off + n, size - n);
+ break;
+
+ default: // error
+ i = -1;
+ break;
+ }
+
+ if (i == -1) {
+ if (zip_eof)
+ return 0;
+ return -1;
+ }
+ n += i;
+ }
+ return n;
+ }
+
+ function zip_inflate(data, offset /*= 0*/ ) {
+ var out, buff;
+ var i, j;
+
+ zip_inflate_start();
+ zip_inflate_data = data;
+ zip_inflate_pos = offset || 0;
+ var last_zip_inflate_pos = -1;
+
+ if (!0) {
+ zip_NEEDBITS(8);
+ var CMF = zip_GETBITS(8);
+ zip_DUMPBITS(8);
+ zip_NEEDBITS(8);
+ var FLG = zip_GETBITS(8);
+ zip_DUMPBITS(8);
+ if ((CMF & 0x0f) !== 8) {
+ throw new Error("Unsupported compression.");
+ }
+ if (FLG & 0x20) {
+ throw new Error("DICT");
+ }
+ if ((CMF * 256 + FLG) % 31 !== 0) {
+ throw new Error("FCHECK");
+ }
+ }
+
+ buff = new Array(1024);
+ out = "";
+ while ((i = zip_inflate_internal(buff, 0, buff.length)) > 0 && last_zip_inflate_pos != zip_inflate_pos) {
+ last_zip_inflate_pos = zip_inflate_pos;
+ for (j = 0; j < i; j++) out += String.fromCharCode(buff[j]);
+ }
+ zip_inflate_data = null; // G.C.
+ return out;
+ }
+
+ return zip_inflate;
+}();
+
+
+
+function swf_inflate(data) {
+ var sig = data.substr(0, 3);
+ if (sig === "FWS") {
+ return data;
+ }
+ if (sig !== "CWS") {
+ throw new Error("Invalid signature: " + sig);
+ }
+ var ss = new SwfStream(data);
+ ss.skip_bytes(4); // Signature, version.
+ var inflated_size = ss.read_uint32();
+ var inflated = zip_inflate(data, 8);
+ if (inflated.length + 8 !== inflated_size) {
+ throw new Error("Inflated size mismatch: expected " + inflated_size + ", got " + inflated.length);
+ }
+ return "FWS" + data.substring(3, 8) + inflated;
+}
+
+
+
+function SwfStream(data) {
+ var m_bytes = data;
+ var m_byte_idx = 0;
+ var m_buf = 0;
+ var m_buf_bits = 0;
+
+ var byte_align = this.byte_align = function() {
+ m_buf_bits = 0;
+ };
+
+ var read_bits = this.read_bits = function(count) {
+ var rc = 0;
+ while (count !== 0) {
+ if (m_buf_bits === 0) {
+ if (m_byte_idx >= m_bytes.length) {
+ throw new Error("EOF");
+ }
+ m_buf = m_bytes.charCodeAt(m_byte_idx++) & 0xff;
+ m_buf_bits = 8;
+ }
+ var cpy_bits = Math.min(count, m_buf_bits);
+ rc = (rc << cpy_bits) | n_hbits8(m_buf, cpy_bits);
+ m_buf = (m_buf << cpy_bits) & 0xff;
+ m_buf_bits -= cpy_bits;
+ count -= cpy_bits;
+ }
+ return rc;
+ };
+
+
+ var read_uint8 = this.read_uint8 = function() {
+ byte_align();
+ return read_bits(8);
+ };
+
+
+ var read_uint16 = this.read_uint16 = function() {
+ var b1 = read_uint8();
+ var b2 = read_uint8() << 8;
+ return b1 | b2;
+ };
+
+
+ var read_uint32 = this.read_uint32 = function() {
+ return read_sint32() >>> 0;
+ };
+
+
+ var read_sint32 = this.read_sint32 = function() {
+ var b1 = read_uint8();
+ var b2 = read_uint8() << 8;
+ var b3 = read_uint8() << 16;
+ var b4 = read_uint8() << 24;
+ return b1 | b2 | b3 | b4;
+ };
+
+
+ var read_fixed8 = this.read_fixed8 = function() {
+ var a = read_uint8();
+ var b = read_uint8();
+ return b + (a / 0x100);
+ };
+
+ var read_fixed = this.read_fixed = function() {
+ var a = read_uint16();
+ var b = read_uint16();
+ return b + (a / 0x10000);
+ };
+
+ var read_bytes = this.read_bytes = function(count) {
+ byte_align();
+ if (m_byte_idx + count > m_bytes.length) {
+ m_byte_idx = m_bytes.length;
+ throw new Error("EOF");
+ }
+ return m_bytes.slice(m_byte_idx, m_byte_idx += count);
+ };
+
+
+ var skip_bytes = this.skip_bytes = function(count) {
+ byte_align();
+ m_byte_idx += count;
+ };
+
+ var n_hbits8 = this.n_hbits8 = function(n, count) {
+ return (n & 0xff) >> (8 - count);
+ };
+
+
+ var n_hbits16 = this.n_hbits16 = function(n, count) {
+ return (n & 0xffff) >> (16 - count);
+ };
+
+
+ var n_lbits16 = this.n_lbits16 = function(n, count) {
+ return n & ((1 << count) - 1);
+ };
+};
+
+
+
+// namespace_info kinds.
+const doabc_CONSTANT_Namespace = 0x08;
+const doabc_CONSTANT_PackageNamespace = 0x16;
+const doabc_CONSTANT_PackageInternalNs = 0x17;
+const doabc_CONSTANT_ProtectedNamespace = 0x18;
+const doabc_CONSTANT_ExplicitNamespace = 0x19;
+const doabc_CONSTANT_StaticProtectedNs = 0x1A;
+const doabc_CONSTANT_PrivateNs = 0x05;
+
+// multiname_info kinds.
+const doabc_CONSTANT_QName = 0x07;
+const doabc_CONSTANT_QNameA = 0x0D;
+const doabc_CONSTANT_RTQName = 0x0F;
+const doabc_CONSTANT_RTQNameA = 0x10;
+const doabc_CONSTANT_RTQNameL = 0x11;
+const doabc_CONSTANT_RTQNameLA = 0x12;
+const doabc_CONSTANT_Multiname = 0x09;
+const doabc_CONSTANT_MultinameA = 0x0E;
+const doabc_CONSTANT_MultinameL = 0x1B;
+const doabc_CONSTANT_MultinameLA = 0x1C;
+
+// option_detail kinds: these plus namespace_info kinds.
+const doabc_CONSTANT_Int = 0x03;
+const doabc_CONSTANT_UInt = 0x04;
+const doabc_CONSTANT_Double = 0x06;
+const doabc_CONSTANT_Utf8 = 0x01;
+const doabc_CONSTANT_True = 0x0B;
+const doabc_CONSTANT_False = 0x0A;
+const doabc_CONSTANT_Null = 0x0C;
+const doabc_CONSTANT_Undefined = 0x00;
+
+// method_info flags.
+const doabc_MF_NEED_ARGUMENTS = 0x01;
+const doabc_MF_NEED_ACTIVATION = 0x02;
+const doabc_MF_NEED_REST = 0x04;
+const doabc_MF_HAS_OPTIONAL = 0x08;
+const doabc_MF_SET_DXNS = 0x40;
+const doabc_MF_HAS_PARAM_NAMES = 0x80;
+
+// traits_info kinds.
+const doabc_Trait_Slot = 0;
+const doabc_Trait_Method = 1;
+const doabc_Trait_Getter = 2;
+const doabc_Trait_Setter = 3;
+const doabc_Trait_Class = 4;
+const doabc_Trait_Function = 5;
+const doabc_Trait_Const = 6;
+
+// traits_info attributes.
+const doabc_ATTR_Final = 0x01;
+const doabc_ATTR_Override = 0x02;
+const doabc_ATTR_Metadata = 0x04;
+
+// instance_info flags.
+const doabc_CONSTANT_ClassSealed = 0x01;
+const doabc_CONSTANT_ClassFinal = 0x02;
+const doabc_CONSTANT_ClassInterface = 0x04;
+const doabc_CONSTANT_ClassProtectedNs = 0x08;
+
+
+
+function doABCReader(bytes) {
+ var m_bytes = bytes;
+ var m_byte_idx = 0;
+
+ var eof = this.eof = function() {
+ return m_byte_idx >= m_bytes.length;
+ };
+
+
+ var read_bytes = this.read_bytes = function(count) {
+ var end = m_byte_idx + count;
+ if (end > m_bytes.length) {
+ m_byte_idx = m_bytes.length;
+ throw new Error("EOF");
+ }
+ var rc = m_bytes.slice(m_byte_idx, end);
+ m_byte_idx = end;
+ return rc;
+ };
+
+ var read_u8 = this.read_u8 = function() {
+ if (eof()) {
+ throw new Error("EOF");
+ }
+ return m_bytes.charCodeAt(m_byte_idx++) & 0xff;
+ };
+
+
+ var read_u16 = this.read_u16 = function() {
+ var b1 = read_u8();
+ var b2 = read_u8();
+ return (b2 << 8) | b1;
+ };
+
+
+ var read_s24 = this.read_s24 = function() {
+ var b1 = read_u8();
+ var b2 = read_u8() << 8;
+ var b3 = read_u8() << 16;
+ var n = b1 | b2 | b3;
+ // 0x800000 is 2^23, 0x1000000 is 2^24.
+ if (n >= 0x800000) {
+ n -= 0x1000000;
+ }
+ return n;
+ };
+
+
+ var read_u32 = this.read_u32 = function() {
+ var n = 0;
+ for (var i = 0; i !== 5; ++i) {
+ var b = read_u8();
+ const has_next = b & 0x80;
+ b &= 0x7f;
+ // Sanity check.
+ if (i === 4) {
+ // The last byte must not have the high bit set.
+ if (has_next) {
+ throw new Error("Invalid stream: high bit is set, but no more bytes needed.");
+ }
+ // The last byte can't have non-zero bits 4-7,
+ // i.e. it can't be greater than 0x0f (bin: 00001111),
+ // otherwise it would overflow the result value: 4*7 bits
+ // in the previous bytes = 28, so there's only 4 bits left,
+ // namely, 0-3.
+ if (b > 0x0f) {
+ throw new Error("Invalid stream: too many bits set in the last byte.");
+ }
+ } // Sanity check.
+ n |= b << (i * 7);
+ if (!has_next) {
+ break;
+ }
+ }
+ return n >>> 0;
+ };
+
+
+ var read_u30 = this.read_u30 = function() {
+ // 0x3fffffff is 2^30 - 1.
+ return read_u32() & 0x3fffffff;
+ };
+
+
+ var read_s32 = this.read_s32 = function() {
+ return read_u32() | 0;
+ };
+
+ var read_d64 = this.read_d64 = function() {
+ // static const boolean little_endian = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1;
+ var _static = arguments.callee;
+ if (_static["doABCReader::little_endian"] === undefined) {
+ _static["doABCReader::little_endian"] = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
+ }
+ var b = new Array(8);
+ for (var i = 0; i !== 8; ++i) {
+ b[i] = read_u8();
+ }
+ if (!_static["doABCReader::little_endian"]) {
+ b.reverse();
+ }
+ return new Float64Array(new Uint8Array(b).buffer)[0];
+ };
+
+
+ var read_cpool_info = this.read_cpool_info = function() {
+ var cp = new doabc_cpool_info();
+
+ var cnt;
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.integers = new Array(cnt);
+ cp.integers[0] = 0;
+ for (var i = 1; i !== cnt; ++i) {
+ cp.integers[i] = read_s32();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.uintegers = new Array(cnt);
+ cp.uintegers[0] = 0;
+ for (var i = 1; i !== cnt; ++i) {
+ cp.uintegers[i] = read_u32();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.doubles = new Array(cnt);
+ cp.doubles[0] = 0;
+ for (var i = 1; i !== cnt; ++i) {
+ cp.doubles[i] = read_d64();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.strings = new Array(cnt);
+ cp.strings[0] = "";
+ for (var i = 1; i !== cnt; ++i) {
+ cp.strings[i] = read_string_info();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.namespaces = new Array(cnt);
+ cp.namespaces[0] = new doabc_namespace_info();
+ for (var i = 1; i !== cnt; ++i) {
+ cp.namespaces[i] = read_namespace_info();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.ns_sets = new Array(cnt);
+ cp.ns_sets[0] = new doabc_ns_set_info();
+ for (var i = 1; i !== cnt; ++i) {
+ cp.ns_sets[i] = read_ns_set_info();
+ }
+ }
+
+ cnt = read_u30();
+ if (cnt !== 0) {
+ cp.multinames = new Array(cnt);
+ cp.multinames[0] = new doabc_multiname_info();
+ for (var i = 1; i !== cnt; ++i) {
+ cp.multinames[i] = read_multiname_info();
+ }
+ }
+
+ return cp;
+ };
+
+
+ var read_string_info = this.read_string_info = function() {
+ var size = read_u30();
+ return size !== 0 ? utf8_decode(read_bytes(size)) : "";
+ };
+
+
+ var read_namespace_info = this.read_namespace_info = function() {
+ var o = {}; //new doabc_namespace_info();
+ o.kind = read_u8();
+ o.name = read_u30();
+ return o;
+ };
+
+
+ var read_ns_set_info = this.read_ns_set_info = function() {
+ var o = {}; //new doabc_ns_set_info();
+ var cnt = read_u8();
+ o.ns = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.ns[i] = read_u30();
+ }
+ return o;
+ };
+
+
+ var read_multiname_info = this.read_multiname_info = function() {
+ var o;
+ var kind = read_u8();
+ switch (kind) {
+ case doabc_CONSTANT_QName:
+ case doabc_CONSTANT_QNameA:
+ o = read_multiname_info_QName();
+ break;
+ case doabc_CONSTANT_RTQName:
+ case doabc_CONSTANT_RTQNameA:
+ o = read_multiname_info_RTQName();
+ break;
+ case doabc_CONSTANT_RTQNameL:
+ case doabc_CONSTANT_RTQNameLA:
+ o = read_multiname_info_RTQNameL();
+ break;
+ case doabc_CONSTANT_Multiname:
+ case doabc_CONSTANT_MultinameA:
+ o = read_multiname_info_Multiname();
+ break;
+ case doabc_CONSTANT_MultinameL:
+ case doabc_CONSTANT_MultinameLA:
+ o = read_multiname_info_MultinameL();
+ break;
+ default:
+ throw new Error("Unexpected multiname kind: " + kind);
+ }
+ o.kind = kind;
+ return o;
+ };
+
+
+ var read_method_info = this.read_method_info = function() {
+ var o = {}; //new doabc_method_info();
+
+ var cnt = read_u30();
+ o.return_type = read_u30();
+
+ o.param_types = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.param_types[i] = read_u30();
+ }
+
+ o.name = read_u30();
+ o.flags = read_u8();
+
+ if (o.flags & doabc_MF_HAS_OPTIONAL) {
+ var cnt = read_u30();
+ o.options = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.options[i] = read_option_detail();
+ }
+ }
+
+ if (o.flags & doabc_MF_HAS_PARAM_NAMES) {
+ var cnt = read_u30();
+ o.param_names = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.param_names[i] = read_u30();
+ }
+ }
+
+ return o;
+ };
+
+
+ var read_metadata_info = this.read_metadata_info = function() {
+ var o = {}; //new doabc_metadata_info();
+ o.name = read_u30();
+ var cnt = read_u30();
+ o.items = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.items[i] = read_item_info();
+ }
+ return o;
+ };
+
+
+ var read_instance_info = this.read_instance_info = function() {
+ var o = {}; //new doabc_instance_info();
+ var cnt;
+
+ o.name = read_u30();
+ o.super_name = read_u30();
+ o.flags = read_u8();
+
+ if (o.flags & doabc_CONSTANT_ClassProtectedNs) {
+ o.protectedNs = read_u30();
+ }
+
+ cnt = read_u30();
+ o.interfaces = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.interfaces[i] = read_u30();
+ }
+
+ o.iinit = read_u30();
+
+ cnt = read_u30();
+ o.traits = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.traits[i] = read_traits_info();
+ }
+
+ return o;
+ };
+
+
+ var read_class_info = this.read_class_info = function() {
+ var o = {}; //new doabc_class_info();
+ o.cinit = read_u30();
+ var cnt = read_u30();
+ o.traits = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.traits[i] = read_traits_info();
+ }
+ return o;
+ };
+
+
+ var read_script_info = this.read_script_info = function() {
+ var o = {}; //new doabc_script_info();
+ o.init = read_u30();
+ var cnt = read_u30();
+ o.traits = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.traits[i] = read_traits_info();
+ }
+ return o;
+ };
+
+
+ var read_method_body_info = this.read_method_body_info = function() {
+ var o = {}; //new doabc_method_body_info();
+ var cnt;
+
+ o.method = read_u30();
+ o.max_stack = read_u30();
+ o.local_count = read_u30();
+ o.init_scope_depth = read_u30();
+ o.max_scope_depth = read_u30();
+
+ cnt = read_u30();
+ o.code = read_bytes(cnt);
+
+ cnt = read_u30();
+ o.exceptions = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.exceptions[i] = read_exception_info();
+ }
+
+ cnt = read_u30();
+ o.traits = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.traits[i] = read_traits_info();
+ }
+
+ return o;
+ };
+
+
+ var read_option_detail = this.read_option_detail = function() {
+ var o = {}; //new doabc_option_detail();
+ o.val = read_u30();
+ o.kind = read_u8();
+ return o;
+ };
+
+
+ var read_item_info = this.read_item_info = function() {
+ var o = {}; //new doabc_item_info();
+ o.key = read_u30();
+ o.val = read_u30();
+ return o;
+ };
+
+
+ var read_exception_info = this.read_exception_info = function() {
+ var o = {}; //new doabc_exception_info();
+ o.from = read_u30();
+ o.to = read_u30();
+ o.target = read_u30();
+ o.exc_type = read_u30();
+ o.var_name = read_u30();
+ return o;
+ };
+
+
+ var read_traits_info = this.read_traits_info = function() {
+ var o = {}; //new doabc_traits_info();
+ o.name = read_u30();
+
+ var kind = read_u8();
+ o.kind = kind & 0x0f;
+ o.attrs = (kind >> 4) & 0x0f;
+
+ switch (o.kind) {
+ case doabc_Trait_Slot:
+ case doabc_Trait_Const:
+ o.trait = read_trait_slot();
+ break;
+ case doabc_Trait_Class:
+ o.trait = read_trait_class();
+ break;
+ case doabc_Trait_Function:
+ o.trait = read_trait_function();
+ break;
+ case doabc_Trait_Method:
+ case doabc_Trait_Getter:
+ case doabc_Trait_Setter:
+ o.trait = read_trait_method();
+ break;
+ default:
+ throw new Error("Unexpected trait kind: " + o.kind);
+ }
+
+ if (o.attrs & doabc_ATTR_Metadata) {
+ var cnt = read_u8();
+ o.metadata = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ o.metadata[i] = read_u30();
+ }
+ }
+
+ return o;
+ };
+
+
+ var read_trait_slot = this.read_trait_slot = function() {
+ var o = {}; //new doabc_trait_slot();
+ o.slot_id = read_u30();
+ o.type_name = read_u30();
+ o.vindex = read_u30();
+ if (o.vindex !== 0) {
+ o.vkind = read_u8();
+ }
+ return o;
+ };
+
+
+ var read_trait_class = this.read_trait_class = function() {
+ var o = {}; //new doabc_trait_class();
+ o.slot_id = read_u30();
+ o.classi = read_u30();
+ return o;
+ };
+
+
+ var read_trait_function = this.read_trait_function = function() {
+ var o = {}; //new doabc_trait_function();
+ o.slot_id = read_u30();
+ o.func = read_u30();
+ return o;
+ };
+
+
+ var read_trait_method = this.read_trait_method = function() {
+ var o = {}; //new doabc_trait_method();
+ o.disp_id = read_u30();
+ o.method = read_u30();
+ return o;
+ };
+
+
+ var read_multiname_info_QName = this.read_multiname_info_QName = function() {
+ var o = {}; //new doabc_multiname_info_QName();
+ o.ns = read_u30();
+ o.name = read_u30();
+ return o;
+ };
+
+
+ var read_multiname_info_RTQName = this.read_multiname_info_RTQName = function() {
+ var o = {}; //new doabc_multiname_info_RTQName();
+ o.name = read_u30();
+ return o;
+ };
+
+
+ var read_multiname_info_RTQNameL = this.read_multiname_info_RTQNameL = function() {
+ // This kind has no associated data.
+ return {}; //new doabc_multiname_info_RTQNameL();
+ };
+
+
+ var read_multiname_info_Multiname = this.read_multiname_info_Multiname = function() {
+ var o = {}; //new doabc_multiname_info_Multiname();
+ o.name = read_u30();
+ o.ns_set = read_u30();
+ return o;
+ };
+
+
+ var read_multiname_info_MultinameL = this.read_multiname_info_MultinameL = function() {
+ var o = {}; //new doabc_multiname_info_MultinameL();
+ o.ns_set = read_u30();
+ return o;
+ };
+}
+
+
+function doabc_namespace_info() {
+ this.kind = 0;
+ this.name = 0;
+}
+
+
+function doabc_ns_set_info() {
+ this.ns = [];
+}
+
+
+function doabc_multiname_info() {
+ this.kind = 0;
+}
+
+
+function doabc_cpool_info() {
+ this.integers = [];
+ this.uintegers = [];
+ this.doubles = [];
+ this.strings = [];
+ this.namespaces = [];
+ this.ns_sets = [];
+ this.multinames = [];
+}
+
+doabc_cpool_info.prototype = {
+ get_item: function(cont, idx) {
+ if (idx < 0 || idx >= cont.length) {
+ throw new Error("Index out of range: " + idx);
+ }
+ return cont[idx];
+ },
+
+ resolve_integer: function(idx) {
+ return this.get_item(this.integers, idx);
+ },
+
+ resolve_uinteger: function(idx) {
+ return this.get_item(this.uintegers, idx);
+ },
+
+ resolve_string: function(idx) {
+ return this.get_item(this.strings, idx);
+ },
+
+ resolve_ns: function(idx) {
+ return this.resolve_string(this.get_item(this.namespaces, idx).name);
+ },
+
+ resolve_multiname: function(idx) {
+ var s = "";
+
+ var mi = this.get_item(this.multinames, idx);
+ switch (mi.kind) {
+ case doabc_CONSTANT_QName:
+ case doabc_CONSTANT_QNameA:
+ if (mi.ns !== 0) {
+ s = this.resolve_ns(mi.ns);
+ }
+ if (s.length !== 0) {
+ s += ".";
+ }
+ s += this.resolve_string(mi.name);
+ break;
+ case doabc_CONSTANT_RTQName:
+ case doabc_CONSTANT_RTQNameA:
+ s = this.resolve_string(mi.name);
+ break;
+ case doabc_CONSTANT_RTQNameL:
+ case doabc_CONSTANT_RTQNameLA:
+ // This kind has no associated data.
+ break;
+ case doabc_CONSTANT_Multiname:
+ case doabc_CONSTANT_MultinameA:
+ // TODO: Implement.
+ throw new Error("Not implemented: doabc_CONSTANT_Multiname(A)");
+ break;
+ case doabc_CONSTANT_MultinameL:
+ case doabc_CONSTANT_MultinameLA:
+ // TODO: Implement.
+ throw new Error("Not implemented: doabc_CONSTANT_MultinameL(A)");
+ break;
+ default:
+ throw new Error("Unexpected multiname kind: " + mi.kind);
+ }
+ return s;
+ },
+
+};
+
+
+
+function doABCFile() {
+ this.major_version = 0;
+ this.minor_version = 0;
+ this.constant_pool = null;
+ this.methods = [];
+ this.metadata = [];
+ this.instances = [];
+ this.classes = [];
+ this.scripts = [];
+ this.method_bodies = [];
+}
+doABCFile.prototype = {
+ get_method_body: function(idx) {
+ var mb = null;
+ this.method_bodies.some(function(o) {
+ return o.method === idx && (mb = o);
+ });
+ return mb;
+ },
+
+ get_method_body_by_name_index: function(cls_name_idx, name_idx) {
+ var inst_idx = this.get_instance_index_by_name_index(cls_name_idx);
+ if (inst_idx === -1) {
+ throw new Error("Class not found: " + cls_name_idx);
+ }
+ return this.get_method_body_by_name_index0(name_idx, this.instances[inst_idx].traits,
+ this.classes[inst_idx].traits);
+ },
+ get_method_body_by_name_index0: function(name_idx, traits) {
+ var cp = this.constant_pool;
+ for (var i = 1, len = arguments.length; i < len; ++i) {
+ var traits = arguments[i];
+ for (var j = 0, jlen = traits.length; j !== jlen; ++j) {
+ var ti = traits[j];
+ if (ti.kind !== doabc_Trait_Method || cp.multinames[ti.name].kind !== doabc_CONSTANT_QName) {
+ continue;
+ }
+ if (ti.name === name_idx) {
+ return this.get_method_body(ti.trait.method);
+ }
+ }
+ }
+ throw new Error("Method not found: " + name_idx);
+ },
+
+ get_instance_index_by_name_index: function(name_idx) {
+ var cp = this.constant_pool,
+ a = this.instances;
+ for (var i = 0, len = a.length; i !== len; ++i) {
+ var ii = a[i];
+ if (cp.multinames[ii.name].kind !== doabc_CONSTANT_QName) {
+ continue;
+ }
+ if (ii.name === name_idx) {
+ return i;
+ }
+ }
+ return -1;
+ }
+};
+
+// ActionScript 3 opcodes.
+const AS3_OP_PUSHSCOPE = 0x30;
+const AS3_OP_PUSHSTRING = 0x2c;
+const AS3_OP_PUSHBYTE = 0x24;
+const AS3_OP_PUSHSHORT = 0x25;
+const AS3_OP_PUSHINT = 0x2d;
+const AS3_OP_PUSHUINT = 0x2e;
+const AS3_OP_GETLOCAL_0 = 0xd0;
+const AS3_OP_GETLOCAL_1 = 0xd1;
+const AS3_OP_GETLOCAL_2 = 0xd2;
+const AS3_OP_GETLOCAL_3 = 0xd3;
+const AS3_OP_GETLOCAL = 0x62;
+const AS3_OP_SETLOCAL_1 = 0xd5;
+const AS3_OP_SETLOCAL_2 = 0xd6;
+const AS3_OP_SETLOCAL_3 = 0xd7;
+const AS3_OP_SETLOCAL = 0x63;
+const AS3_OP_CALLPROPERTY = 0x46;
+const AS3_OP_CONSTRUCTPROP = 0x4a;
+const AS3_OP_CALLPROPVOID = 0x4f;
+const AS3_OP_COERCE = 0x80;
+const AS3_OP_COERCE_S = 0x85;
+const AS3_OP_FINDPROPSTRICT = 0x5d;
+const AS3_OP_FINDPROPERTY = 0x5e;
+const AS3_OP_RETURNVOID = 0x47;
+const AS3_OP_RETURNVALUE = 0x48;
+const AS3_OP_GETLEX = 0x60;
+const AS3_OP_IFTRUE = 0x11;
+const AS3_OP_SETPROPERTY = 0x61;
+const AS3_OP_GETPROPERTY = 0x66;
+const AS3_OP_MODULO = 0xa4;
+
+function utf8_decode(str) {
+ var a = [];
+ for (var i = 0, len = str.length; i < len; ++i) {
+ var cc = str.charCodeAt(i);
+ if (cc > 255) {
+ throw new Error("Illegal character: must be in range [0; 255]: " + cc);
+ }
+ if (cc < 0x80) {
+ a.push(str.charAt(i));
+ continue;
+ }
+ var n = 0;
+ var num_bytes = 0;
+ // 110xxxxx 10xxxxxx
+ if ((cc & 0xe0) === 0xc0) {
+ num_bytes = 1;
+ n = cc & 0x1f;
+ }
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ else if ((cc & 0xf0) === 0xe0) {
+ num_bytes = 2;
+ n = cc & 0x0f;
+ }
+ // Other is not supported, because we have only 16 bits for code points.
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ else {
+ throw new Error("Code point too big.");
+ }
+ var j = i + 1,
+ j_end = j + num_bytes;
+ if (j_end > len) {
+ throw new Error("Premature end of input string.");
+ }
+ for (; j !== j_end; ++j) {
+ cc = str.charCodeAt(j);
+ if (cc > 255) {
+ throw new Error("Illegal character: must be in range [0; 255]: " + cc);
+ }
+ if ((cc & 0xc0) !== 0x80) {
+ throw new Error("Illegal character: high bits must be 10: " + cc);
+ }
+ n <<= 6;
+ n |= cc & 0x3f;
+ }
+ a.push(String.fromCharCode(n));
+ i = j_end - 1;
+ }
+ return a.join("");
+}
+
+
+
+function get_simple_date_str() {
+ var now = new Date();
+ var y = now.getFullYear();
+ var m = now.getMonth() + 1;
+ var d = now.getDate();
+ return "" + y + "-" + (m < 10 ? "0" : "") + m + "-" + (d < 10 ? "0" : "") + d;
+}
+
+
+function Stopwatch() {
+ this.start_times = {};
+ this.end_times = {};
+}
+Stopwatch.prototype = {
+ start: function(name /*= null*/ ) {
+ this.start_times[name] = Date.now();
+ this.end_times[name] = 0;
+ },
+
+ stop: function(name /*= null*/ ) {
+ this.end_times[name] = Date.now();
+ },
+
+ time: function(name /*= null*/ ) {
+ return (this.end_times[name] || Date.now()) - this.start_times[name];
+ }
+};
+
+
+function refresh_signature_func(ctx) {
+ var df = parse_swf(ctx);
+ if (!df) {
+ return;
+ }
+
+ var stopwatch = new Stopwatch();
+ stopwatch.start();
+ var rc = decode(df);
+ if (!rc) {
+ return;
+ }
+ var code = [
+ "/* Not encoded. */",
+ "if (params.stream.sig) { return params.stream.sig; }",
+ "/* " + get_simple_date_str() + ": " + String(ctx.file).replace(/[\\*]/g, "_") + " */",
+ "var s = params.stream.s;",
+ "if (!s) { return ''; }",
+ "var swap = params.swap;",
+ "var a = s.split('');"
+ ];
+ for (var i = 0, len = rc.calls.length; i !== len; ++i) {
+ var o = rc.calls[i];
+ switch (o.name) {
+ case "swap":
+ code.push("swap(a, " + o.arg + ");");
+ break;
+ case "clone":
+ code.push("a = a.slice(" + o.arg + ");");
+ break;
+ case "reverse":
+ code.push("a.reverse();");
+ break;
+ default:
+ return;
+ }
+ }
+ code.push("return a.join('');");
+ stopwatch.stop();
+ log("Got signature function in " + stopwatch.time() + " ms.");
+ return {
+ timestamp: rc.timestamp,
+ func_text: code.join(" ")
+ };
+}
+
+
+function Decoder(file, reader, states, idx /*= 0*/ ) {
+ this.result = {
+ timestamp: -1,
+ calls: []
+ };
+ this.file = file;
+ this.reset(reader, states, idx);
+}
+Decoder.prototype = {
+ run: function() {
+ var done = false;
+ while (!done && !this.reader.eof()) {
+ var res;
+ var o = this.parse_op();
+ if (!o) {
+ break;
+ }
+ var sv = this.states[this.idx];
+ switch (typeof(sv)) {
+ case "number":
+ res = this.advance_if(o.op === sv);
+ break;
+ case "function":
+ res = sv.call(this, o.op, o);
+ break;
+ default:
+ throw new Error("Invalid state type: " + typeof(sv));
+ }
+ if (!res) {
+ done = res === null;
+ break;
+ }
+ }
+ return done ? this.result : null;
+ },
+ parse_op: function() {
+ var o = {};
+ var dar = this.reader;
+ switch (o.op = dar.read_u8()) {
+ case AS3_OP_COERCE_S:
+ case AS3_OP_GETLOCAL_0:
+ case AS3_OP_GETLOCAL_1:
+ case AS3_OP_GETLOCAL_2:
+ case AS3_OP_GETLOCAL_3:
+ case AS3_OP_MODULO:
+ case AS3_OP_PUSHSCOPE:
+ case AS3_OP_SETLOCAL_1:
+ case AS3_OP_SETLOCAL_2:
+ case AS3_OP_SETLOCAL_3:
+ case AS3_OP_RETURNVALUE:
+ case AS3_OP_RETURNVOID:
+ break;
+ case AS3_OP_PUSHBYTE:
+ o.value = dar.read_u8();
+ break;
+ case AS3_OP_PUSHSHORT:
+ o.value = dar.read_u30();
+ break;
+ case AS3_OP_COERCE:
+ case AS3_OP_FINDPROPERTY:
+ case AS3_OP_FINDPROPSTRICT:
+ case AS3_OP_GETLEX:
+ case AS3_OP_GETLOCAL:
+ case AS3_OP_GETPROPERTY:
+ case AS3_OP_PUSHINT:
+ case AS3_OP_PUSHSTRING:
+ case AS3_OP_PUSHUINT:
+ case AS3_OP_SETLOCAL:
+ case AS3_OP_SETPROPERTY:
+ o.index = dar.read_u30();
+ break;
+ case AS3_OP_IFTRUE:
+ o.offset = dar.read_s24();
+ break;
+ case AS3_OP_CALLPROPERTY:
+ case AS3_OP_CALLPROPVOID:
+ case AS3_OP_CONSTRUCTPROP:
+ o.index = dar.read_u30();
+ o.arg_count = dar.read_u30();
+ break;
+ default:
+ return null;
+ }
+ return o;
+ },
+ advance_if: function(cond) {
+ return cond ? ++this.idx : false;
+ },
+ switch_if: function(cond, states, idx /*= 0*/ ) {
+ if (!cond) {
+ return false;
+ }
+ this.reset(this.reader, states, idx);
+ return true;
+ },
+ done_if: function(cond) {
+ return cond ? null : false;
+ },
+ reset: function(reader, states, idx /*= 0*/ ) {
+ this.reader = reader;
+ this.states = states;
+ this.idx = idx || 0;
+ },
+};
+
+function decode(df) {
+ var cp = df.constant_pool;
+ var inst_idx = -1;
+ for (var i = 0, len = df.instances.length; i !== len; ++i) {
+ var ii = df.instances[i];
+ if (cp.multinames[ii.name].kind !== doabc_CONSTANT_QName) {
+ continue;
+ }
+ if (cp.resolve_multiname(ii.name) === "com.google.youtube.util.SignatureDecipher") {
+ inst_idx = i;
+ break;
+ }
+ }
+ if (inst_idx === -1) {
+ return;
+ }
+ var mb_cinit, mb_decipher;
+ var cls = df.classes[inst_idx];
+ mb_cinit = df.get_method_body(cls.cinit);
+ if (!mb_cinit) {
+ return;
+ }
+ for (var i = 0, len = cls.traits.length; i !== len; ++i) {
+ var ti = cls.traits[i];
+ if (ti.kind !== doabc_Trait_Method || cp.multinames[ti.name].kind !== doabc_CONSTANT_QName) {
+ continue;
+ }
+ var s_name = cp.resolve_multiname(ti.name);
+ if (s_name === "decipher") {
+ if (mb_decipher) {
+ return;
+ }
+ mb_decipher = df.get_method_body(ti.trait.method);
+ if (!mb_decipher) {
+ return;
+ }
+ }
+ }
+ if (!mb_decipher) {
+ return;
+ }
+
+ var ctx = {
+ cls_name_idx: -1,
+ func_name_idx: -1,
+ name_by_index: {},
+ call_arg: null
+ };
+ var PS_TIMESTAMP = [
+ function(op, o) {
+ return op !== AS3_OP_FINDPROPERTY || cp.resolve_multiname(o.index) !== "TIMESTAMP" || this.advance_if(true);
+ },
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_PUSHSHORT && (this.result.timestamp = o.value, 1)) || this.advance_if(op === AS3_OP_PUSHINT && (this.result.timestamp = cp.resolve_integer(o.index), 1)) || this.advance_if(op === AS3_OP_PUSHUINT && (this.result.timestamp = cp.resolve_uinteger(o.index), 1));
+ },
+ function(op) {
+ if (op !== AS3_OP_SETPROPERTY) {
+ return false;
+ }
+ this.reset(new doABCReader(mb_decipher.code), PS_DECIPHER);
+ return true;
+ }
+ ];
+ var PS_DECIPHER = [
+ AS3_OP_GETLOCAL_0,
+ AS3_OP_PUSHSCOPE,
+ AS3_OP_GETLEX,
+ AS3_OP_IFTRUE,
+ AS3_OP_FINDPROPERTY,
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_FINDPROPSTRICT && (ctx.cls_name_idx = o.index));
+ },
+ AS3_OP_CONSTRUCTPROP,
+ AS3_OP_SETPROPERTY,
+ AS3_OP_GETLEX,
+ AS3_OP_GETLOCAL_1,
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_PUSHSTRING && cp.resolve_string(o.index).length === 0);
+ },
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_CALLPROPERTY && cp.resolve_multiname(o.index) === "http://adobe.com/AS3/2006/builtin.split");
+ },
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_CALLPROPERTY && (ctx.func_name_idx = o.index));
+ },
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_PUSHSTRING && cp.resolve_string(o.index).length === 0);
+ },
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_CALLPROPERTY && cp.resolve_multiname(o.index) === "http://adobe.com/AS3/2006/builtin.join");
+ },
+ function(op) {
+ if (op !== AS3_OP_RETURNVALUE) {
+ return false;
+ }
+ var mb = this.file.get_method_body_by_name_index(ctx.cls_name_idx, ctx.func_name_idx);
+ if (!mb) {
+ return false;
+ }
+ this.reset(new doABCReader(mb.code), PS_FUNC);
+ return true;
+ }
+ ];
+ var PS_FUNC = [
+ AS3_OP_GETLOCAL_0,
+ function(op) {
+ return this.switch_if(op === AS3_OP_PUSHSCOPE, PS_FUNC_BRANCH);
+ },
+ ];
+ var PS_FUNC_BRANCH = [
+ function(op) {
+ return this.switch_if(op === AS3_OP_GETLOCAL_0, PS_FUNC_CALL) || this.advance_if(op === AS3_OP_GETLOCAL_1);
+ },
+ function(op) {
+ return this.done_if(op === AS3_OP_RETURNVALUE);
+ }
+ ];
+ var PS_FUNC_CALL = [
+ AS3_OP_GETLOCAL_1,
+ function(op, o) {
+ return this.advance_if(op === AS3_OP_PUSHBYTE && (ctx.call_arg = o.value, 1));
+ },
+ function(op, o) {
+ if (op !== AS3_OP_CALLPROPERTY) {
+ return false;
+ }
+ var func_name_idx = o.index;
+ var func_name = ctx.name_by_index[func_name_idx];
+ if (!func_name) {
+ var mb = this.file.get_method_body_by_name_index(ctx.cls_name_idx, func_name_idx);
+ if (!mb) {
+ return false;
+ }
+ var PS_TEST = [
+ AS3_OP_GETLOCAL_0,
+ AS3_OP_PUSHSCOPE,
+ AS3_OP_GETLOCAL_1,
+ function(op) {
+ return this.done_if((op === AS3_OP_GETLOCAL_2 && (this.result = "clone")) || (op === AS3_OP_CALLPROPVOID && (this.result = "reverse")) || (op === AS3_OP_PUSHBYTE && (this.result = "swap")));
+ }
+ ];
+ var d = new Decoder(df, new doABCReader(mb.code), PS_TEST);
+ if (d.run()) {
+ func_name = d.result;
+ }
+ if (!func_name) {
+ return false;
+ }
+ ctx.name_by_index[func_name_idx] = func_name;
+ }
+ this.result.calls.push({
+ name: func_name,
+ arg: ctx.call_arg
+ });
+ return this.advance_if(true);
+ },
+ function(op) {
+ return op === AS3_OP_COERCE || this.switch_if(op === AS3_OP_SETLOCAL_1, PS_FUNC_BRANCH);
+ }
+ ];
+
+ var d = new Decoder(df, new doABCReader(mb_cinit.code), PS_TIMESTAMP);
+ return d.run();
+}
+
+
+
+function parse_swf(ctx) {
+ var stopwatch = new Stopwatch();
+
+ stopwatch.start();
+ var swf_inflated = swf_inflate(ctx.bytes);
+ stopwatch.stop();
+ log("SWF inflated in " + stopwatch.time() + " ms.");
+ ctx.bytes = null;
+
+ stopwatch.start();
+ var bs = new SwfStream(swf_inflated);
+ bs.skip_bytes(8); // Signature, version, size.
+ var num_bits = bs.read_bits(5);
+ bs.read_bits(num_bits);
+ bs.read_bits(num_bits);
+ bs.read_bits(num_bits);
+ bs.read_bits(num_bits);
+ bs.skip_bytes(4); // Frame rate, frame count.
+
+ var df = null;
+ for (;;) {
+ var t = bs.read_uint16();
+ var tag_type = bs.n_hbits16(t, 10);
+ var tag_len = bs.n_lbits16(t, 6);
+ if (tag_len === 0x3f) {
+ tag_len = bs.read_sint32();
+ }
+ if (0 === tag_type) {
+ break;
+ }
+ if (tag_type !== 82) {
+ bs.skip_bytes(tag_len);
+ continue;
+ }
+
+ var bytes = bs.read_bytes(tag_len);
+ var dar = new doABCReader(bytes);
+ for (var i = 0; i !== 4; ++i) {
+ dar.read_u8();
+ }
+ while (dar.read_u8() !== 0) {}
+ df = new doABCFile();
+ df.minor_version = dar.read_u16();
+ df.major_verison = dar.read_u16();
+ df.constant_pool = dar.read_cpool_info();
+
+ var cnt;
+ cnt = dar.read_u30();
+ df.methods = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.methods[i] = dar.read_method_info();
+ }
+
+ cnt = dar.read_u30();
+ df.metadata = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.metadata[i] = dar.read_metadata_info();
+ }
+
+ cnt = dar.read_u30();
+ df.instances = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.instances[i] = dar.read_instance_info();
+ }
+ df.classes = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.classes[i] = dar.read_class_info();
+ }
+
+ cnt = dar.read_u30();
+ df.scripts = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.scripts[i] = dar.read_script_info();
+ }
+
+ cnt = dar.read_u30();
+ df.method_bodies = new Array(cnt);
+ for (var i = 0; i !== cnt; ++i) {
+ df.method_bodies[i] = dar.read_method_body_info();
+ }
+
+ break;
+ }
+ stopwatch.stop();
+ log("SWF parsed in " + stopwatch.time() + " ms.");
+
+ return df;
+}
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/metacafe.js b/data/extensions/html5-video-everywhere@lejenome.me/data/metacafe.js
new file mode 100644
index 0000000..e84db57
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/metacafe.js
@@ -0,0 +1,71 @@
+(function() {
+ "use strict";
+
+ onReady(() => {
+ if (/watch\/\d+\/.*/.test(location.pathname))
+ watchPage();
+ else if (/[^\/]+\/?$/.test(location.pathname))
+ channelPage();
+ });
+
+ function watchPage() {
+ var ob, url;
+ if ((ob = document.getElementById("flashVars"))) {
+ url = getURL(ob.value);
+ } else if ((ob = document.getElementById("FlashWrap")) &&
+ (ob = ob.getElementsByTagName("video")).length) {
+ url = ob[0].src;
+ ob[0].pause();
+ ob[0].remove();
+ }
+ if (!url)
+ return;
+ var container = document.getElementById("ItemContainer");
+ if (!container)
+ return;
+ var vp = new VP(container);
+ vp.addSrc(url, "medium", "mp4");
+ vp.props({
+ autoplay: autoPlay(true),
+ preload: preLoad(),
+ loop: isLoop(),
+ controls: true
+ });
+ vp.style({
+ width: "100%"
+ });
+ vp.setup();
+ }
+
+ 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 container = document.getElementById("ItemContainer");
+ //var container = embed.parentElement;
+ var vp = new VP(container);
+ vp.addSrc(url, "medium", "mp4");
+ vp.props({
+ autoplay: autoPlay(false),
+ preload: preLoad(),
+ loop: isLoop(),
+ controls: true
+ });
+ vp.style({
+ width: "100%"
+ });
+ vp.setup();
+ });
+ }
+
+ 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/data/video-player.js b/data/extensions/html5-video-everywhere@lejenome.me/data/video-player.js
new file mode 100644
index 0000000..64d3957
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/video-player.js
@@ -0,0 +1,387 @@
+/* global VP:true, LBP */
+"use strict";
+const VP = function(container) {
+ this.attached = false;
+ this.player = undefined;
+ this.container = container;
+ this._srcs = [];
+ this._style = {};
+ this._containerStyle = {};
+ this._props = {};
+ this._langs = [];
+ this._containerProps = {};
+ this._CSSRules = [];
+ this.styleEl = undefined;
+};
+VP.prototype = {};
+VP.prototype.addSrc = function(url, qlt, cdc) {
+ this.log("addSrc", qlt, cdc);
+ this._srcs[Qlt.indexOf(qlt) * 2 + Cdc.indexOf(cdc)] = url;
+};
+VP.prototype.srcs = function(fmts, wrapper, get) {
+ var slct, i, j;
+ if (!wrapper) {
+ for (slct in fmts) {
+ i = Qlt.indexOf(slct.split("/")[0]);
+ j = Cdc.indexOf(slct.split("/")[1]);
+ this._srcs[i * 2 + j] = fmts[slct];
+ }
+ return;
+ }
+ for (i = 0; i < Qlt.length; i++) {
+ for (j = 0; j < Cdc.length; j++) {
+ slct = Qlt[i] + "/" + Cdc[j];
+ if (!(slct in wrapper) || !fmts[wrapper[slct]])
+ continue;
+ this._srcs[i * 2 + j] = (get) ?
+ (get(fmts[wrapper[slct]]) || this._srcs[i * 2 + j]) : fmts[wrapper[slct]];
+ }
+ }
+};
+VP.prototype.mainSrcIndex = function() {
+ var i, j, slct;
+ i = OPTIONS.prefQlt;
+ while (i > -1) {
+ if (this._srcs[i * 2 + OPTIONS.prefCdc])
+ return {
+ qlt: i,
+ cdc: OPTIONS.prefCdc
+ };
+ else if (this._srcs[i * 2 + (OPTIONS.prefCdc + 1 % 2)])
+ return {
+ qlt: i,
+ cdc: OPTIONS.prefCdc + 1 % 2
+ };
+ i = (i >= OPTIONS.prefQlt) ? i + 1 : i - 1;
+ if (i > 3)
+ i = OPTIONS.prefQlt - 1;
+ }
+};
+VP.prototype.setup = function() {
+ var idx = this.mainSrcIndex();
+ if (!idx)
+ return this.error("Failed to find video url");
+ this.clean();
+ // just to force contextmenu id. TODO: fix contextmenu and use createNode
+ this.container.innerHTML = "<video contextmenu='h5vew-contextmenu'></video>";
+ this.player = this.container.firstChild;
+ // if (!this.player) {
+ // this.player = createNode("video", this._props, this._style);
+ // }
+ if (!this.styleEl)
+ this.styleEl = createNode("style");
+ this.patch(this.player, this._props);
+ this.patch(this.player, this._style, "style");
+ this.player.appendChild(createNode("source", {
+ src: this._srcs[idx.qlt * 2 + idx.cdc],
+ type: "video/" + Cdc[idx.cdc]
+ }));
+ this._srcs.forEach((url, i) => {
+ if (i !== idx.qlt * 2 + idx.cdc)
+ this.player.appendChild(createNode("source", {
+ src: url,
+ type: "video/" + Cdc[i % 2]
+ }));
+ });
+ this.container.appendChild(this.player);
+ this.container.appendChild(this.styleEl);
+ this.attached = true;
+ this.slctLang();
+ this._CSSRules.forEach(s => this.styleEl.sheet.insertRule(s,
+ this.styleEl.sheet.cssRules.length));
+ this.patch(this.container, this._containerProps);
+ this.patch(this.container, this._containerStyle, "style");
+ this.log("setup");
+ if (OPTIONS.player === 1)
+ this.setupLBP();
+ else
+ this.setupContextMenu(idx);
+};
+VP.prototype.tracksList = function(langs, fnct) {
+ this._langs = langs.sort();
+ this._slctLang = fnct;
+ if (this.attached)
+ this.slctLang();
+};
+VP.prototype.slctLang = function(lang) {
+ if (!(lang !== undefined || OPTIONS.lang !== 0) || this._slctLang === undefined)
+ return;
+ if (lang === undefined)
+ lang = LANGS[OPTIONS.lang - 1];
+ if (this._lang)
+ this.player.textTracks.getTrackById(this._lang).mode = "disabled";
+ var track;
+ if ((track = this.player.textTracks.getTrackById(lang))) {
+ track.mode = "showing";
+ this._lang = lang;
+ } else {
+ new Promise((resolve, reject) => this._slctLang(lang, resolve, reject))
+ .then((url) => {
+ track = createNode("track", {
+ kind: "subtitles",
+ id: lang,
+ src: url,
+ label: lang,
+ srclang: lang
+ });
+ this.player.appendChild(track);
+ track.track.mode = "showing";
+ this._lang = lang;
+ });
+ }
+};
+VP.prototype.on = function(evt, cb) {
+ this.player["on" + evt] = cb; //TODO
+};
+VP.prototype.stop = function() {
+ this.log("stop");
+ if (!this.player)
+ return;
+ this.player.pause();
+ this.player.onended = undefined;
+ if (this.player.duration)
+ this.player.currentTime = this.player.duration;
+};
+VP.prototype.clean = function() {
+ this.log("clean");
+ if (this.player) {
+ this.player.pause();
+ this.player.onended = undefined;
+ }
+ // site default video player sometime continue playing on background
+ var vds = this.container.getElementsByTagName("video");
+ for (var i = 0; i < vds.length; i++) {
+ if (this.player === vds[i])
+ continue;
+ vds[i].pause();
+ vds[i].src = "";
+ vds[i].addEventListener("playing", (e) => {
+ e.currentTarget.pause();
+ e.currentTarget.src = "";
+ });
+ }
+ rmChildren(this.container);
+ this.attached = false;
+};
+VP.prototype.end = function() {
+ this.log("end");
+ this.stop();
+ this.clean();
+ this._srcs = {};
+ this._style = {};
+ this._containerStyle = {};
+ this._props = {};
+ this._containerProps = {};
+ this._sheets = [];
+};
+VP.prototype.addCSSRule = function(cssText) {
+ this.log("addCSSRule", cssText);
+ this._CSSRules.push(cssText);
+ if (this.attached)
+ this.styleEl.sheet.insertRule(cssText,
+ this.styleEl.sheet.cssRules.length);
+};
+VP.prototype.style = function(style) {
+ this.apply(style, this.player, "_style", "style");
+};
+VP.prototype.containerStyle = function(style) {
+ this.apply(style, this.container, "_containerStyle", "style");
+};
+VP.prototype.props = function(props) {
+ this.apply(props, this.player, "_props");
+};
+VP.prototype.containerProps = function(props) {
+ this.apply(props, this.container, "_containerProps");
+};
+VP.prototype.error = function(msg) {
+ this.log("ERROR Msg:", msg);
+ this.clean();
+ if (!this.styleEl)
+ this.styleEl = createNode("style");
+ this.container.appendChild(createNode("p", {
+ textContent: "Ooops! :("
+ }, {
+ padding: "15px",
+ fontSize: "20px"
+ }));
+ this.container.appendChild(createNode("p", {
+ textContent: msg
+ }, {
+ fontSize: "20px"
+ }));
+ this.container.appendChild(this.styleEl);
+ this._CSSRules.forEach(s => this.styleEl.sheet.insertRule(s,
+ this.styleEl.sheet.cssRules.length));
+ this.patch(this.container, this._containerProps);
+ this.patch(this.container, this._containerStyle, "style");
+};
+VP.prototype.setupLBP = function() {
+ this.container.className += " leanback-player-video";
+ LBP.setup();
+ this.player.style = "";
+ this.player.style = "";
+ this.player.style.position = "relative";
+ this.player.style.height = "inherit";
+ this.container.style.marginLeft = "0px";
+};
+VP.prototype.setupContextMenu = function(idx) {
+ /* jshint maxstatements:false */
+ this._contextMenu = createNode("menu", {
+ type: "context", //"popup",
+ id: "h5vew-contextmenu"
+ });
+ var qltMenu = createNode("menu", {
+ id: "h5vew-menu-qlt",
+ label: "Video Quality"
+ });
+ for (var i = 0; i < Qlt.length; i++)
+ qltMenu.appendChild(createNode("menuitem", {
+ type: "radio",
+ label: Qlt[i],
+ radiogroup: "menu-qlt",
+ checked: (idx.qlt === i),
+ disabled: !(this._srcs[i * 2] || this._srcs[i * 2 + 1]),
+ onclick: (e) => {
+ idx.qlt = Qlt.indexOf(e.target.label);
+ idx.cdc = (this._srcs[idx.qlt * 2 + idx.cdc]) ?
+ idx.cdc : (idx.cdc + 1 % 2);
+ var paused = this.player.paused;
+ this.player.src = this._srcs[idx.qlt * 2 + idx.cdc] +
+ "#t=" + this.player.currentTime;
+ this.player.load();
+ this.player.oncanplay = () => {
+ if (!paused)
+ this.player.play();
+ this.player.oncanplay = undefined;
+ };
+ }
+ }));
+ var cdcMenu = createNode("menu", {
+ id: "h5vew-menu-cdc",
+ label: "Preferred Video Format"
+ });
+ for (i = 0; i < Cdc.length; i++)
+ cdcMenu.appendChild(createNode("menuitem", {
+ type: "radio",
+ label: Cdc[i],
+ radiogroup: "menu-cdc",
+ checked: (OPTIONS.prefCdc === i),
+ onclick: (e) =>
+ chgPref("prefCdc", Cdc.indexOf(e.target.label))
+ }));
+ var langMenu = createNode("menu", {
+ id: "h5vew-menu-lang",
+ label: "Subtitles"
+ });
+ langMenu.appendChild(createNode("menuitem", {
+ type: "radio",
+ label: "none",
+ radiogroup: "menu-lang",
+ checked: OPTIONS.lang === 0 || this._langs.findIndex((l) => l === LANGS[OPTIONS.lang - 1]) === -1,
+ onclick: (e) => {
+ if (this._lang === undefined)
+ return;
+ this.player.textTracks.getTrackById(this._lang).mode = "disabled";
+ this._lang = undefined;
+ }
+ }));
+ for (i = 0; i < this._langs.length; i++)
+ langMenu.appendChild(createNode("menuitem", {
+ type: "radio",
+ label: this._langs[i],
+ radiogroup: "menu-lang",
+ checked: this._langs[i] === LANGS[OPTIONS.lang - 1],
+ onclick: (e) =>
+ this.slctLang(e.target.label)
+ }));
+ var loopMenu = createNode("menu", {
+ id: "h5vew-menu-loop",
+ label: "Loop Video"
+ });
+ ["Never", "Always", "Default"].forEach((n, i) => {
+ loopMenu.appendChild(createNode("menuitem", {
+ type: "radio",
+ label: n,
+ radiogroup: "menu-loop",
+ checked: (OPTIONS.loop === i),
+ onclick: (e) =>
+ chgPref("loop", i)
+ }));
+ });
+ var autoNextMenu = createNode("menuitem", {
+ id: "h5vew-menu-autonext",
+ type: "checkbox",
+ label: "Auto Play Next Video",
+ checked: OPTIONS.autoNext,
+ onclick: (e) => chgPref("autoNext", e.target.checked)
+ });
+ var moreMenu = createNode("menu", {
+ id: "h5vew-menu-more",
+ label: "More options"
+ });
+ var copyMenu = createNode("menuitem", {
+ id: "h5vew-menu-copy",
+ label: "Copy Page URL",
+ onclick: () => setClipboard(location.href) // TODO
+ });
+ var disableMenu = createNode("menuitem", {
+ id: "h5vew-menu-disable",
+ label: "Disable " + OPTIONS.driver.charAt(0).toUpperCase() +
+ OPTIONS.driver.slice(1) + " Support",
+ onclick: () => {
+ self.port.emit("disable");
+ this._contextMenu.removeChild(disableMenu);
+ }
+ });
+ var aboutMenu = createNode("menuitem", {
+ id: "h5vew-menu-about",
+ label: "About HTML5 Video EveryWhere",
+ onclick: () =>
+ window.open("http://lejenome.github.io/html5-video-everywhere#v=" +
+ OPTIONS.addon.version + "&id=" + OPTIONS.addon.id,
+ "h5vew-about", "width=550,height=280,menubar=no,toolbar=no,location=no,status=no,chrome=on,modal=on")
+ });
+ moreMenu.appendChild(copyMenu);
+ moreMenu.appendChild(disableMenu);
+ moreMenu.appendChild(createNode("hr"));
+ moreMenu.appendChild(aboutMenu);
+
+ const prefChanged = (name) => {
+ if (name === "autoNext")
+ autoNextMenu.checked = OPTIONS.autoNext;
+ };
+ onPrefChange.push(prefChanged);
+ this._contextMenu.appendChild(qltMenu);
+ this._contextMenu.appendChild(cdcMenu);
+ if (this._langs.length > 0)
+ this._contextMenu.appendChild(langMenu);
+ this._contextMenu.appendChild(loopMenu);
+ this._contextMenu.appendChild(autoNextMenu);
+ this._contextMenu.appendChild(moreMenu);
+ this.container.appendChild(this._contextMenu);
+ // TODO: fix assigning contextMenu and uncommant createNode("video") ^
+ this.container.contextmenu = "h5vew-contextmenu";
+};
+VP.prototype.apply = function(props, el, obj, sub) {
+ for (var prop in props) {
+ if (props.hasOwnProperty(prop)) {
+ this[obj][prop] = props[prop];
+ if (this.attached && sub)
+ el[sub][prop] = props[prop];
+ else if (this.attached && !sub)
+ el[prop] = props[prop];
+ }
+ }
+};
+VP.prototype.patch = function(el, props, sub) {
+ for (var prop in props)
+ if (props.hasOwnProperty(prop))
+ if (sub)
+ el[sub][prop] = props[prop];
+ else
+ el[prop] = props[prop];
+};
+VP.prototype.log = function(...args) {
+ args.unshift("[DRIVER::VP]");
+ dump(args.join(" ") + "\n");
+}; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/vimeo.js b/data/extensions/html5-video-everywhere@lejenome.me/data/vimeo.js
new file mode 100644
index 0000000..1e8df2b
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/vimeo.js
@@ -0,0 +1,137 @@
+(function() {
+ "use strict";
+
+ onReady(() =>
+ getConfig().then(getVideoInfo)
+ );
+
+ function injectPlayer(conf) {
+ try {
+ let player_container, player, stl;
+ if (conf.isEmbed) {
+ player_container = document.body;
+ } else if (conf.isWatch) {
+ player_container = document.getElementById("video") ||
+ document.getElementById("video_wrapper");
+ if ((stl = player_container.children[0]) &&
+ (stl = stl.sheet) &&
+ (stl.cssRules.length > 0)) {
+ stl = stl.cssRules[0].cssText;
+ }
+ } else {
+ player_container = document.getElementById("clip_" + conf.id);
+ }
+ if (!player_container)
+ return;
+ var vp = new VP(player_container);
+ vp.srcs(conf.fmts, {
+ "high/mp4": "hd",
+ "medium/mp4": "sd",
+ "low/mp4": "mobile"
+ }, (fmt) => fmt.url);
+ vp.props({
+ className: conf.className,
+ autoplay: autoPlay(),
+ preload: preLoad(),
+ loop: isLoop(),
+ controls: true,
+ poster: conf.poster,
+ volume: OPTIONS.volume / 100
+ });
+ vp.tracksList(conf.tracks.map(l => l.lang), (lang, resolve, reject) => {
+ var l = conf.tracks.find(l => l.lang === lang);
+ if (l === undefined)
+ reject();
+ else
+ resolve(l.direct_url || l.url);
+ });
+ if (stl)
+ vp.addCSSRule(stl);
+ vp.setup();
+ if (conf.isWatch)
+ brozarEvents();
+ } catch (e) {
+ logify("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) ||
+ ogType().indexOf("video") > -1;
+ var isEmbed = /https?:\/\/player.vimeo.com\/video/.test(location.href);
+ var isChannel = /https?:\/\/vimeo.com\/(channels\/|)\w+/.test(location.href) ||
+ ogType().match(/channel|profile/) !== null;
+ 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);
+ conf.fmts = data.request.files.h264;
+ conf.poster = data.video.thumbs.base;
+ conf.tracks = data.request.text_tracks || [];
+ return Promise.resolve(conf);
+ };
+ const INFO_URL = "//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);
+ }
+ }
+
+ function brozarEvents() {
+ // change Vimeo default click events of items on brozar element
+ var clips = document.getElementById("clips");
+ if (clips)
+ clips.onclick = function(e) {
+ if (e.target === e.currentTarget)
+ return;
+ var li = e.target;
+ while (li.tagName !== "LI")
+ li = li.parentElement;
+ window.location = "/" + li.id.replace("clip_", "");
+ };
+ var promos = document.getElementsByClassName("js-promo_link");
+ var promoClick = function(e) {
+ window.location = "/" + e.currentTarget.dataset.clipId;
+ };
+ for (var i = 0; promos && i < promos.length; i++)
+ promos[i].onclick = promoClick;
+ }
+
+ function ogType() {
+ var t = document.head.querySelector("meta[property=\"og:type\"]");
+ return (t) ? t.content : "";
+ }
+}()); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/data/youtube-formats.js b/data/extensions/html5-video-everywhere@lejenome.me/data/youtube-formats.js
new file mode 100644
index 0000000..e23cf83
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/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/data/youtube.js b/data/extensions/html5-video-everywhere@lejenome.me/data/youtube.js
new file mode 100644
index 0000000..aa1c666
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/data/youtube.js
@@ -0,0 +1,330 @@
+/*globals FMT_WRAPPER*/
+(function() {
+ "use strict";
+ var vp;
+ var swf_url;
+
+ onReady(() => {
+ changePlayer();
+ window.addEventListener("spfrequest", function() {
+ if (vp)
+ vp.stop();
+ });
+ window.addEventListener("spfdone", function() {
+ changePlayer();
+ });
+ });
+
+ function changePlayer() {
+ getConfig()
+ .then(getVideoInfo)
+ .then((conf) => {
+ try {
+ if (vp)
+ vp.end();
+ var player_container = getPlayerContainer(conf);
+ if (!player_container)
+ return;
+ var seek = getSeek();
+ vp = new VP(player_container);
+ vp.srcs(conf.fmts, FMT_WRAPPER, (fmt) => fmt.url + seek);
+ //vp.containerProps({
+ // className: conf.className || ""
+ //});
+ vp.props({
+ id: "video_player",
+ className: conf.className || "",
+ autoplay: autoPlay(location.search.search("autoplay=") === -1 ? !conf.isEmbed : location.search.search("autoplay=0") === -1),
+ preload: preLoad(),
+ loop: isLoop(location.search.search("loop=1") !== -1),
+ controls: true,
+ poster: conf.poster || "",
+ volume: OPTIONS.volume / 100
+ });
+ //vp.style({
+ // position: "relative"
+ //});
+ vp.tracksList((conf.tracks || []).map(i => i.lc), (lang, resolve, reject) => {
+ var o = conf.tracks.find((i) => i.lc === lang);
+ if (o === undefined)
+ return reject();
+ addWebVTT(lang, o.u, resolve, reject);
+ });
+ vp.setup();
+ if (conf.isWatch)
+ playNextOnFinish();
+ } catch (e) {
+ logify("EXCEPTION: unexpected error on changePlayer",
+ e.lineNumber, e.columnNumber, e.message, e.stack);
+ }
+ })
+ .catch((rej) => {
+ if (rej === undefined)
+ return;
+ switch (rej.error) {
+ case "VIDEO_URL_UNACCESSIBLE":
+ if (rej.data.reason)
+ errorMessage("Failed to load video url with the following error message: " +
+ rej.data.reason, rej.conf);
+ break;
+ case "NO_SUPPORTED_VIDEO_FOUND":
+ errorMessage("Failed to find any playable video url." +
+ (rej.unsig ? " All urls are not signed" : ""), rej.conf);
+ break;
+ default:
+ logify("EXCEPTION: unexpected error on changePlayer", rej);
+ break;
+ }
+ });
+ }
+
+ function errorMessage(msg, conf) {
+ var error_container;
+ if (vp)
+ vp.end();
+ if (conf)
+ error_container = getPlayerContainer(conf);
+ if (!error_container)
+ error_container = document.getElementById("player-unavailable") || document.getElementById("player");
+ if (!error_container)
+ return;
+ vp = new VP(error_container);
+ vp.srcs(conf.fmts, FMT_WRAPPER);
+ if (conf && conf.isWatch)
+ vp.containerProps({
+ className: " player-height player-width player-api"
+ });
+ if (conf && conf.isChannel)
+ vp.containerProps({
+ className: " c4-player-container"
+ }); //" html5-main-video";
+ if (conf && conf.isEmbed) {
+ vp.containerProps({
+ className: " full-frame"
+ });
+ }
+ vp.containerStyle({
+ background: "linear-gradient(to bottom, #383838 0px, #131313 100%) repeat scroll 0% 0% #262626"
+ });
+ vp.error(msg);
+ }
+
+ 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 conf = {};
+ conf.isEmbed = location.pathname.startsWith("/embed/");
+ conf.isWatch = location.pathname.startsWith("/watch");
+ conf.isChannel = location.pathname.startsWith("/channel/") || location.pathname.startsWith("/user/");
+ conf.withoutCookies = location.hostname.search("youtube-nocookie.com") > -1;
+ if (!conf.isEmbed && !conf.isWatch && !conf.isChannel)
+ reject();
+ if (conf.isEmbed) {
+ conf.id = location.pathname.match(/^\/embed\/([^?#/]*)/)[1];
+ conf.className = "full-frame";
+ } else if (conf.isChannel) {
+ var upsell = document.getElementById("upsell-video");
+ if (!upsell)
+ reject();
+ conf.id = upsell.dataset["videoId"];
+ conf.className = "c4-player-container"; //+ " html5-main-video"
+ } else {
+ conf.id = location.search.slice(1).match(/v=([^/?#]*)/)[1];
+ conf.className = "player-width player-height player-api";
+ }
+ if (!conf.id)
+ reject({
+ error: "PLAYER_ID_NOT_FOUND",
+ conf: conf
+ });
+ else
+ resolve(conf);
+ });
+ }
+
+ function getVideoInfo(conf) {
+ return new Promise((resolve, reject) => {
+ var INFO_URL = "https://www.youtube.com/get_video_info?html5=1&hl=en_US&el=detailpage&video_id=";
+ if (conf.withoutCookies)
+ INFO_URL = "https://www.youtube-nocookie.com/get_video_info?html5=1&hl=en_US&el=detailpage&video_id=";
+ if (unsafeWindow.ytplayer && unsafeWindow.ytplayer.config) {
+ conf.info = unsafeWindow.ytplayer.config.args.url_encoded_fmt_stream_map;
+ conf.poster = unsafeWindow.ytplayer.config.args.iurlsd ||
+ unsafeWindow.ytplayer.config.args.iurl ||
+ unsafeWindow.ytplayer.config.args.iurlhq ||
+ unsafeWindow.ytplayer.config.args.iurlmaxres ||
+ unsafeWindow.ytplayer.config.args.iurlmq;
+ if (unsafeWindow.ytplayer.config.args.caption_tracks)
+ conf.tracks = parse(unsafeWindow.ytplayer.config.args.caption_tracks, true);
+ swf_url = unsafeWindow.ytplayer.config.url;
+ resolve(conf);
+ } else {
+ asyncGet(INFO_URL + conf.id, {}, "text/plain").then((data) => {
+ if (data.endsWith("="))
+ try {
+ data = atob(data);
+ } catch (_) {}
+ data = parse(data);
+ if (data.status === "fail") {
+ return reject({
+ error: "VIDEO_URL_UNACCESSIBLE",
+ data: data,
+ conf: conf
+ });
+ }
+ // get the poster url
+ if (data.iurlhq)
+ conf.poster = data.iurlhq;
+ // extract avalable formats to fmts object
+ conf.info = data.url_encoded_fmt_stream_map;
+ if (data.caption_tracks)
+ conf.tracks = parse(data.caption_tracks, true);
+ resolve(conf);
+ });
+ }
+ }).then((conf) => {
+ var player = createNode("video");
+ var unsignedVideos = false;
+ conf.fmts = {};
+ parse(conf.info, true)
+ .filter(it5 => {
+ if (player.canPlayType(it5.type) !== "probably")
+ return false;
+ if (it5.url.search("signature=") === -1) {
+ unsignedVideos = true;
+ if (!OPTIONS.genYTSign)
+ return false;
+ }
+ return true;
+ })
+ .forEach(fmt => {
+ conf.fmts[fmt.itag] = fmt;
+ });
+ if (unsignedVideos && OPTIONS.genYTSign) {
+ return fixSignature(conf);
+ } else {
+ return Promise.resolve(conf);
+ }
+ });
+ }
+
+ function fixSignature(conf) {
+ return new Promise((resolve, reject) => {
+ self.port.emit("fix_signature", {
+ fmts: conf.fmts,
+ swf_url: swf_url
+ });
+ self.port.on("fixed_signature", (fmts) => {
+ conf.fmts = fmts;
+ logify("fixed Signature");
+ resolve(conf);
+ });
+ });
+ }
+
+ function playNextOnFinish() {
+ //Credits to @durazell github.com/lejenome/youtube-html5-player/issues/9
+ if (document.getElementsByClassName("playlist-header").length > 0) {
+ vp.on("ended", function(e) {
+ if (this.currentTime !== this.duration || OPTIONS.autoNext === false)
+ return;
+ var cur = 0,
+ len = 0;
+ var current, playlist;
+ if ((current = document.getElementsByClassName("currently-playing")).length > 0) {
+ cur = parseInt(current[0].dataset["index"]) + 1;
+ } else if ((current = document.getElementById("playlist-current-index"))) {
+ cur = parseInt(current.textContent);
+ }
+ if ((playlist = document.getElementsByClassName("playlist-videos-list")).length > 0) {
+ len = playlist[0].childElementCount;
+ } else if ((playlist = document.getElementById("playlist-length"))) {
+ len = parseInt(playlist.textContent);
+ }
+
+ if (isNaN(cur) === true || isNaN(len) === true) {
+ logify("Cannot find location in playlist, autoplay failed");
+ return;
+ }
+
+ if (cur < len) {
+ window.location.href = document.getElementsByClassName("yt-uix-scroller-scroll-unit")[cur].getElementsByTagName("a")[0].href;
+ }
+ });
+ }
+ }
+
+ function parse(data, splitComma) {
+ if (splitComma) {
+ return data.split(",").map(i => parse(i));
+ } else {
+ var res = {};
+ var nv;
+ data.split("&").forEach((p) => {
+ try {
+ nv = p.split("=").map(function(v) {
+ return decodeURIComponent(v.replace(/\+/g, " "));
+ });
+ if (!(nv[0] in res)) res[nv[0]] = nv[1];
+ } catch (e) {}
+ });
+ return res;
+ }
+ }
+
+ function addWebVTT(lang, url, resolve, reject) {
+ asyncGet(url).then((data) => {
+ var webvtt = "WEBVTT\n\n";
+ var XMLParser = new DOMParser();
+ var xml = XMLParser.parseFromString(data, "text/xml");
+ if (xml.documentElement.nodeName !== "transcript")
+ reject();
+ var els = xml.documentElement.childNodes;
+ for (var i = 0; i < els.length; i++) {
+ var start = els[i].attributes.getNamedItem("start");
+ var dur = els[i].attributes.getNamedItem("dur");
+ if (start === null || dur === null)
+ continue;
+ start = parseFloat(start.value);
+ dur = parseFloat(dur.value);
+ var s = start % 60;
+ var m = (start - s) / 60;
+ var tl1 = "" + (m < 10 ? "0" : "") + m + ":" +
+ (s < 10 ? "0" : "") + s.toFixed(3);
+ s = (start + dur) % 60;
+ m = (start + dur - s) / 60;
+ var tl2 = "" + (m < 10 ? "0" : "") + m + ":" +
+ (s < 10 ? "0" : "") + s.toFixed(3);
+
+ webvtt += (i + 1) + "\n" + tl1 + " --> " + tl2 + "\n" + els[i].textContent + "\n\n";
+ }
+ resolve("data:text/vtt;base64," + btoa(window.unescape(
+ encodeURIComponent(webvtt.replace("&#39;", "'", "g")))));
+ });
+ }
+
+ function getSeek() {
+ var seek = 0;
+ if (location.search.search("start=") > -1) {
+ seek = location.search.match(/start=(\d+)/);
+ seek = seek ? parseInt(seek[1]) : 0;
+ } else if (location.search.search(/[&?]t=\d/) > -1) {
+ seek = location.search.match(/[&?]t=([^&]*)/)[1];
+ var h = seek.match(/(\d+)h/);
+ var m = seek.match(/(\d+)m/);
+ var s = seek.match(/(\d+)s/) || seek.match(/^(\d+)$/);
+ seek = (h ? parseInt(h[1]) : 0) * 3600 +
+ (m ? parseInt(m[1]) : 0) * 60 +
+ (s ? parseInt(s[1]) : 0);
+ }
+ return seek > 0 ? ("#t=" + seek) : "";
+ }
+}()); \ No newline at end of file