summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@gnu.org>2015-10-10 11:26:33 -0500
committerRuben Rodriguez <ruben@gnu.org>2015-10-12 23:20:55 -0500
commit3bd364a1a8dee1316bd5c432229d83a30822927b (patch)
tree692784ee28f1ecb741addf5106b3e733ec67a3f1
parentee08985f3bbf56ad8fda61c7370b6b37e1bbbe16 (diff)
HTML5 Video Everywhere updated to 0.3.3
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/LICENSE363
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/META-INF/manifest.mf164
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.rsabin4192 -> 4192 bytes
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.sf4
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/Makefile18
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/README.md39
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/TODO.md25
-rw-r--r--[-rwxr-xr-x]data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js355
-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
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/icon.pngbin0 -> 6535 bytes
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/index.js151
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/install.rdf57
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/break.js9
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/common.js20
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/dailymotion.js9
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/facebook.js7
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/flashgot-YouTube.js535
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/metacafe.js11
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/vimeo.js11
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/lib/youtube.js30
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/package.json311
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/break.md5
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/dailymotion.md5
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/facebook.md11
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/metacafe.md10
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/vimeo.md15
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/spec/youtube.md27
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/test/test-main.js13
-rw-r--r--data/extensions/html5-video-everywhere@lejenome.me/test/test.html41
38 files changed, 5189 insertions, 430 deletions
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/LICENSE b/data/extensions/html5-video-everywhere@lejenome.me/LICENSE
new file mode 100644
index 0000000..e87a115
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/LICENSE
@@ -0,0 +1,363 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+1.8. "License"
+
+ means this document.
+
+1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+Exhibit A - Source Code Form License Notice
+
+ 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/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a
+notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
+
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/manifest.mf b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/manifest.mf
index 8b51fb4..72cd1a5 100644
--- a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/manifest.mf
+++ b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/manifest.mf
@@ -2,126 +2,176 @@ Manifest-Version: 1.0
Name: install.rdf
Digest-Algorithms: MD5 SHA1
-MD5-Digest: yEAlVKMLjXkyf3c7msk/Xw==
-SHA1-Digest: aV3Z43FdsOjtb5MVBqTufnvUCLc=
+MD5-Digest: 3CZKpd7ahCT81kRmeoqgZw==
+SHA1-Digest: Oc1Ig4LQZBBJ9qhZ/J7NIzXwAN8=
+
+Name: icon.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dmpm2FIs94bBxuVOhXTB4w==
+SHA1-Digest: zIzMCJJ0LBAMeZQ7pr9TO3Ir9uY=
Name: bootstrap.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: 7e6z9LJUzPhqfgyfhRMzhA==
-SHA1-Digest: TWD0b5BkAoKXr56l0Tt3AkKBy8s=
+MD5-Digest: gE+jXuKpPkTxUv6AL2Q+0w==
+SHA1-Digest: zJpzqwwkcqSyH1WTx95W5OVwAf8=
+
+Name: index.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: HOjkR7QIIXjQPk1jYs58Lw==
+SHA1-Digest: RxVAcn572CkaXY3rsxFvIVVl0JU=
-Name: harness-options.json
+Name: Makefile
Digest-Algorithms: MD5 SHA1
-MD5-Digest: gvOukOdXNjdHv1ejWNp02g==
-SHA1-Digest: kbPOKwGp8XnWtsH95t0fwLRplOE=
+MD5-Digest: O8EMb/Pvu1YkocCav1nEyw==
+SHA1-Digest: uZslA8OM6foJrLvzmAwDpj++dsw=
-Name: locales.json
+Name: package.json
Digest-Algorithms: MD5 SHA1
-MD5-Digest: p3Qh60/6wDH/UunTuTWZjQ==
-SHA1-Digest: DBci+JD/520hUnFSB3zB1xoBE9g=
+MD5-Digest: xxRAx+XLx0NLnwkT8R8tPA==
+SHA1-Digest: jiG7sIifE2PiFl+gbCi07N1lxI4=
-Name: options.xul
+Name: README.md
Digest-Algorithms: MD5 SHA1
-MD5-Digest: AQXhzeAfLxO+ATnTSo9pOw==
-SHA1-Digest: TjNQdfc9jutGAHq9GjWhCrjsXaI=
+MD5-Digest: T5XE19z7qJAXJk6z6NZ6Ng==
+SHA1-Digest: I4F+gaDIe3IIBpiojcLyl2oxCig=
-Name: defaults/preferences/prefs.js
+Name: TODO.md
Digest-Algorithms: MD5 SHA1
-MD5-Digest: WB3cSv+b4ydlRWW5JKfkyw==
-SHA1-Digest: 8NhNf95wV6r8Pj6T2VaLw4URH/k=
+MD5-Digest: MA5+pBVvw/JwLi1MaG3cAQ==
+SHA1-Digest: T/OmE2mQtQvuJKMh6imYM8vn13A=
-Name: resources/html5-video-everywhere/data/break.js
+Name: data/break.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: FHcsZl9Qe91hW/7B28cAkg==
SHA1-Digest: P4o5B+pFXkcUyTcjR/EjVPN2NEY=
-Name: resources/html5-video-everywhere/data/common.js
+Name: data/common.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: E1LUgC77SvIagwSzhOELtQ==
-SHA1-Digest: RKAZ/SxZXihI9RR/YuPqx/qr+Zo=
+MD5-Digest: T1pz4K8CA/GEgrWW/MhdMg==
+SHA1-Digest: z0vDbg2HnjR62lXA2DxtQMBorkI=
-Name: resources/html5-video-everywhere/data/dailymotion.js
+Name: data/dailymotion.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: ozG1xmyo2629YYbN1ZP18Q==
-SHA1-Digest: 9opU+TINoR5HlMlK1LTq29yB3OA=
+MD5-Digest: 9QsYcMzrj1tL8wW/7bG5Dg==
+SHA1-Digest: LgyuBZytMRtvZ8x+smrqI9E/ufU=
-Name: resources/html5-video-everywhere/data/facebook.js
+Name: data/facebook.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: fqr4Z17t/ZoygcVknd9/dg==
-SHA1-Digest: xicvIjTGA2Usu3fRfOkDnoEZaek=
+MD5-Digest: VItINacQJvbb3wtkPu8o8Q==
+SHA1-Digest: zYMOQvETe6RBJybYc/ErviyavGI=
-Name: resources/html5-video-everywhere/data/flashgot-YouTubeSwf.js
+Name: data/flashgot-YouTubeSwf.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: T+XZ+Rd72kqQauBCH92lDQ==
SHA1-Digest: FqZ/r+c3xYHqFzMwYAQLk2OP9vU=
-Name: resources/html5-video-everywhere/data/metacafe.js
+Name: data/metacafe.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: NMql8+nLTPMdxjV6sP5H3g==
-SHA1-Digest: q2qpkNvUhobvaJjcc7UalhgXnMI=
+MD5-Digest: AAukiZ3WX6dt2AmEGM+1Ew==
+SHA1-Digest: Nl+P9MCFy6YmrQUDabBfQi2tdSM=
-Name: resources/html5-video-everywhere/data/video-player.js
+Name: data/video-player.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: GdLZBfcj0UrWd0diFLtwlQ==
-SHA1-Digest: T4kSzQs0WwEMwBTvWXR0zG9Xvio=
+MD5-Digest: QaVP15oXFYBib7qhCa7Uhg==
+SHA1-Digest: 0o5gijudH3zYgut+Dm7h+MHJWw4=
-Name: resources/html5-video-everywhere/data/vimeo.js
+Name: data/vimeo.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: vysLIrQbnaQs04x+JUaY1A==
-SHA1-Digest: /4NusOTf5vM0OvXpI/gBGnd+CwU=
+MD5-Digest: zmNcKF1Swbah6zoT76rdOw==
+SHA1-Digest: 9mmwDqe6FRUdwpYD8sTwz9LDEKE=
-Name: resources/html5-video-everywhere/data/youtube-formats.js
+Name: data/youtube-formats.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: ba8pxu4YWbMTFLI7u9nSww==
SHA1-Digest: 8LdbGx/9NDqLQ9CndverrJzTRHA=
-Name: resources/html5-video-everywhere/data/youtube.js
+Name: data/youtube.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: fw7qzIDcMToQ8yY0VkEdqQ==
-SHA1-Digest: ezxXLeySGAqP/Yh/E3UCTu1F/RE=
+MD5-Digest: e8sjyWmwQH4By8KTou2qCA==
+SHA1-Digest: IKTdbDBdFlsMpiB2Lucw+sPu7KU=
-Name: resources/html5-video-everywhere/lib/break.js
+Name: lib/break.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: Gs/Etew95x/lD3IuZifl5Q==
SHA1-Digest: 56GIkHz/2jJL9bEjPkLPdO1KVNo=
-Name: resources/html5-video-everywhere/lib/common.js
+Name: lib/common.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: CYP8cXv4SBDfwNklEF7UmA==
SHA1-Digest: 5B8qBt1SCvK4GERTM/ggXyZLYiM=
-Name: resources/html5-video-everywhere/lib/dailymotion.js
+Name: lib/dailymotion.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: G7beTZLJ9bV8qd4TQKvSJA==
SHA1-Digest: rg2Qw46iUoN3IjqEDdcklKTq3XM=
-Name: resources/html5-video-everywhere/lib/facebook.js
+Name: lib/facebook.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: MwgClTBiBe7LFJNcvKMjlg==
SHA1-Digest: H9dSJUDuos2GyVC5dqLB/wMH+9Q=
-Name: resources/html5-video-everywhere/lib/flashgot-YouTube.js
-Digest-Algorithms: MD5 SHA1
-MD5-Digest: VHCubRXtltPxbjJwQSP8Ug==
-SHA1-Digest: ejl5VDFw9wkD6xs+QZGKxD0B6jw=
-
-Name: resources/html5-video-everywhere/lib/main.js
+Name: lib/flashgot-YouTube.js
Digest-Algorithms: MD5 SHA1
-MD5-Digest: R6NltxG2mAW+bFuh2zJOdQ==
-SHA1-Digest: HjEEU999PhXM4vX4gski8wIY058=
+MD5-Digest: seLzlTcid+3/YXgxPdG1Tg==
+SHA1-Digest: zls6CmxZnpdcaPPP45RHJ81BDGc=
-Name: resources/html5-video-everywhere/lib/metacafe.js
+Name: lib/metacafe.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: Kapqu2JlNqdfYVl1mzWZVQ==
SHA1-Digest: Wk6FJJqfUJsTY4EsqXHkk9hMkmc=
-Name: resources/html5-video-everywhere/lib/vimeo.js
+Name: lib/vimeo.js
Digest-Algorithms: MD5 SHA1
MD5-Digest: jTJdcUeScUvccb3lLljoNg==
SHA1-Digest: PFedn4/SHpnfvE32ZXSLJON1SYg=
-Name: resources/html5-video-everywhere/lib/youtube.js
+Name: lib/youtube.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: F0G4vKBsjJ07Z8pkZI5+mQ==
+SHA1-Digest: 1w6nKvceNhIWU8LPJBLX6oqnDEY=
+
+Name: spec/break.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: qObenD1cChTuZxNttmn8Aw==
+SHA1-Digest: u8vX080vxN6pKgXo+CRKX3t7Hfo=
+
+Name: spec/dailymotion.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 6lOpkYUWAsStXLMAqYehBw==
+SHA1-Digest: pGabm+cMpoBvLDdeVvgsOihEzLc=
+
+Name: spec/facebook.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: X5yfYREVbfMy6lPPaaNh6A==
+SHA1-Digest: +O7MYdK6qk7i4psroLVB4+oBux8=
+
+Name: spec/metacafe.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Ccmmf8BrP/cR16sRrKluhw==
+SHA1-Digest: O+/IGkknW0DRL30cmp/Nw7yHRcA=
+
+Name: spec/vimeo.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: mpBaRof9+UzM7MVWZ/vhSg==
+SHA1-Digest: HvRfky4y+7xvDJCO0a/q/BhCJOg=
+
+Name: spec/youtube.md
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zL3rprD0FLrgFRnMt17ztQ==
+SHA1-Digest: OfrOKYbNk4NKiQ478VugyHdGciw=
+
+Name: test/test-main.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: m0uIaXfcS3BiM+JWkuCe4Q==
+SHA1-Digest: P3vJbOqaMLoWNFciqi8Yca0yrJI=
+
+Name: test/test.html
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /0sS5m/n7HFEua6UBE3xEA==
+SHA1-Digest: dhJ2ptKWNvsmAyD6Zyse3h5hfIU=
+
+Name: LICENSE
Digest-Algorithms: MD5 SHA1
-MD5-Digest: 2iKx56tEhaAJbSLMWZITlA==
-SHA1-Digest: nEY1iWkxNKagLglR5KVwjS+meYU=
+MD5-Digest: ZdJvzC816moYGsd35C2x6g==
+SHA1-Digest: +nxNdbrjpkHR+atd8CgXW/uKaco=
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.rsa b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.rsa
index 71cd3a1..a3d4961 100644
--- a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.rsa
+++ b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.rsa
Binary files differ
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.sf b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.sf
index fdecacb..7538a8b 100644
--- a/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.sf
+++ b/data/extensions/html5-video-everywhere@lejenome.me/META-INF/mozilla.sf
@@ -1,4 +1,4 @@
Signature-Version: 1.0
-MD5-Digest-Manifest: rXdZTR03/BLV1sP4JNWVTA==
-SHA1-Digest-Manifest: F+qwFdUpvRczR7PLQrIdFhIzwPE=
+MD5-Digest-Manifest: Hml9wnbFfErJ0P5PjR7X/Q==
+SHA1-Digest-Manifest: I1SMUhwUPiokL1DHydczQRljGvY=
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/Makefile b/data/extensions/html5-video-everywhere@lejenome.me/Makefile
new file mode 100644
index 0000000..3f1fc1b
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/Makefile
@@ -0,0 +1,18 @@
+# List of drivers to enable on build
+
+.NOTPARALLEL : all
+all: lint beautify build
+lint:
+ jshint --verbose *.js */*.js
+beautify:
+ find . -maxdepth 2 -name "*.js" -a ! -name "flashgot-*.js" \
+ | xargs js-beautify -r
+ find . -name "*.json" | xargs -n 1 jsonlint -i
+build:
+ jpm xpi
+run:
+ jpm run
+watch:
+ jpm watchpost --post-url http://localhost:8888/
+test:
+ jpm test
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/README.md b/data/extensions/html5-video-everywhere@lejenome.me/README.md
new file mode 100644
index 0000000..457e9fd
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/README.md
@@ -0,0 +1,39 @@
+# HTML5 Video EveryWhere
+
+Not just an other HTML5 player extension.
+This extension, unlike other extensions, will replace some video streaming sites
+video player by Firefox native player. No just replacing Flash player by the
+site HTML5 player version, but, booth the site HTML5 and Flash player with Firefox
+native player.
+
+**NOTE:**
+This extension will change the page content of the supported video streaming
+sites, as a result, many extensions that depends on this content will no longer
+work as expected.
+
+## Build
+
+`jpm` is required to build the addon. To install `jpm`, run:
+```shell
+npm install -g jpm
+```
+
+To build the addon:
+```shell
+jpm xpi
+```
+
+## Credit
+
+YouTube signature decoder code (data/flashgot-YouTubeSwf.js,
+lib/flashgot-YouTube.js) was copied from the [GPL](
+http://www.gnu.org/copyleft/gpl.html) licenced
+[flashgot](https://flashgot.net/) extension with some code removed and
+other added code under the same licence.
+
+## Licence
+
+This extension is free software; it is distributed under the MPL 2.0 Licence.
+
+Copyright (c) 2014-2015, Moez Bouhlel (bmoez.j@gmail.com) & [The
+Contributors](https://github.com/lejenome/html5-video-everywhere/graphs/contributors)
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/TODO.md b/data/extensions/html5-video-everywhere@lejenome.me/TODO.md
new file mode 100644
index 0000000..2aaffca
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/TODO.md
@@ -0,0 +1,25 @@
+A wichlist of Sites to support:
+ - Youtube
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/YouTube support)]
+ - Facebook
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/Facebook Support)]
+ - Vimeo
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/Vimeo Support)]
+ - Dailymotion
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/Dailymotion Support)]
+ - Break
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/Break Support)]
+ - Metacafe
+ [[status](https://github.com/lejenome/html5-video-everywhere/milestones/Metacafe Support)]
+ - Youku
+ - Blip
+ - Liveleak
+ - Vine
+
+Live Streaming sites (require support of DASH and HLS : [#9](
+https://github.com/lejenome/html5-video-everywhere/issues/9) and [#10](
+https://github.com/lejenome/html5-video-everywhere/issues/10))
+ - Yahoo screen
+ - ustream
+
+For current status of sites in progress, view [spec/](spec/) folder.
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js b/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js
index 840103a..4866564 100755..100644
--- a/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js
+++ b/data/extensions/html5-video-everywhere@lejenome.me/bootstrap.js
@@ -1,350 +1,11 @@
/* 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;
-}
+"use strict";
+
+const { utils: Cu } = Components;
+const rootURI = __SCRIPT_URI_SPEC__.replace("bootstrap.js", "");
+const COMMONJS_URI = "resource://gre/modules/commonjs";
+const { require } = Cu.import(COMMONJS_URI + "/toolkit/require.js", {});
+const { Bootstrap } = require(COMMONJS_URI + "/sdk/addon/bootstrap.js");
+const { startup, shutdown, install, uninstall } = new Bootstrap(rootURI);
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
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/icon.png b/data/extensions/html5-video-everywhere@lejenome.me/icon.png
new file mode 100644
index 0000000..4f5ebda
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/icon.png
Binary files differ
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/index.js b/data/extensions/html5-video-everywhere@lejenome.me/index.js
new file mode 100644
index 0000000..fca20cf
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/index.js
@@ -0,0 +1,151 @@
+/* jshint esnext:true, node:true*/
+"use strict";
+const {
+ Cc, Ci, Cr
+} = require("chrome");
+const {
+ add, remove
+} = require("sdk/util/array");
+const _self = require("sdk/self");
+const pageMod = require("sdk/page-mod");
+const events = require("sdk/system/events");
+const utils = require("sdk/window/utils");
+const clipboard = require("sdk/clipboard");
+var prefs = require("sdk/simple-prefs").prefs;
+// list of current workers
+const workers = [];
+const pageMods = {};
+const common = require("./lib/common");
+const allDrivers = {
+ "facebook": require("./lib/facebook"),
+ "vimeo": require("./lib/vimeo"),
+ "dailymotion": require("./lib/dailymotion"),
+ "break": require("./lib/break"),
+ "metacafe": require("./lib/metacafe"),
+ "youtube": require("./lib/youtube")
+};
+const drivers = Object.keys(allDrivers).filter(drvName =>
+ prefs["disable" + drvName] === false
+);
+
+//ensure preferences match the state of disabled drivers
+Object.keys(allDrivers).filter(drvName =>
+ drivers.indexOf(drvName) === -1
+).forEach(drvName =>
+ prefs["disable" + drvName] = true
+);
+
+
+const onWorkerAttach = (drvName, listen) => (worker) => {
+ logify("onAttach", worker);
+ //send current Addon preferences to content-script
+ let _prefs = {};
+ for (let pref in prefs)
+ _prefs[pref] = prefs[pref];
+ _prefs.driver = drvName;
+ _prefs.addon = {
+ id: _self.id,
+ version: _self.version
+ };
+ worker.port.emit("preferences", _prefs);
+ add(workers, worker);
+ worker.port.on("prefChang", (pref) =>
+ prefs[pref.name] = pref.val);
+ worker.port.on("disable", () =>
+ prefs["disable" + drvName] = true);
+ worker.port.on("setClipboard", (txt) => clipboard.set(txt));
+ for (let evt in listen) {
+ logify("Add listener:", evt);
+ worker.port.on(evt, (obj) => {
+ listen[evt](obj, worker);
+ });
+ }
+ worker.on("detach", function(e) {
+ remove(workers, this);
+
+ });
+};
+
+drivers.forEach(setupDriver);
+
+function setupDriver(drvName) {
+ var driver = allDrivers[drvName];
+ if (driver.match === void(0))
+ return;
+ var scripts, styles;
+ scripts = common.inject.concat(driver.inject)
+ .map(i => _self.data.url(i));
+ styles = common.style.concat(driver.style || [])
+ .map(i => _self.data.url(i));
+ pageMods[drvName] = pageMod.PageMod({
+ include: driver.match,
+ contentScriptFile: scripts,
+ contentStyleFile: styles,
+ contentScriptWhen: driver.when || "ready",
+ onAttach: onWorkerAttach(drvName, driver.listen)
+ });
+}
+
+function listener(event) {
+ var channel = event.subject.QueryInterface(Ci.nsIHttpChannel);
+ var url = event.subject.URI.spec;
+ for (let drvName of drivers) {
+ var driver = allDrivers[drvName];
+ 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));
+ logify("Redirect:", url);
+ return;
+ }
+ }
+ for (let block of(driver.block || [])) {
+ if (block.test(url)) {
+ channel.cancel(Cr.NS_BINDING_ABORTED);
+ logify("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 if (pref.startsWith("disable")) {
+ let drvName = /^disable(.+)/.exec(pref)[1];
+ if (prefs[pref] === false) {
+ add(drivers, drvName);
+ setupDriver(drvName);
+ } else {
+ remove(drivers, drvName);
+ pageMods[drvName].destroy();
+ }
+ } else
+ workersPrefHandler(pref);
+});
+
+function workersPrefHandler(pref) {
+ for (let worker of workers)
+ worker.port.emit("prefChanged", {
+ name: pref,
+ value: prefs[pref]
+ });
+}
+
+function logify(...args) {
+ args.unshift("[CORE]");
+ dump(args.join(" ") + "\n");
+}
+
+exports.main = () => {
+ 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/install.rdf b/data/extensions/html5-video-everywhere@lejenome.me/install.rdf
index 550a5c5..7004330 100644
--- a/data/extensions/html5-video-everywhere@lejenome.me/install.rdf
+++ b/data/extensions/html5-video-everywhere@lejenome.me/install.rdf
@@ -1,27 +1,36 @@
-<?xml version='1.0' encoding='utf-8'?>
+<?xml version="1.0" encoding="utf-8"?>
<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.2.38.1-signed</em:version>
- <em:type>2</em:type>
- <em:bootstrap>true</em:bootstrap>
- <em:unpack>false</em:unpack>
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>html5-video-everywhere@lejenome.me</em:id>
+ <em:type>2</em:type>
+ <em:bootstrap>true</em:bootstrap>
+ <em:unpack>false</em:unpack>
+ <em:version>0.3.3</em:version>
+ <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:optionsURL>data:text/xml,&lt;placeholder/&gt;</em:optionsURL>
+ <em:optionsType>2</em:optionsType>
+ <em:multiprocessCompatible>true</em:multiprocessCompatible>
- <!-- 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>
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>38.0a1</em:minVersion>
+ <em:maxVersion>39.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>
-
- <em:contributor>HTML5 Video Everywhere Contributors (https://github.com/lejenome/html5-video-everywhere/graphs/contributors)</em:contributor><em:targetApplication><Description><em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id><em:minVersion>26.0</em:minVersion><em:maxVersion>30.0a1</em:maxVersion></Description></em:targetApplication></Description>
-</RDF> \ No newline at end of file
+ <em:targetApplication>
+ <Description>
+ <em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id>
+ <em:minVersion>38.0a1</em:minVersion>
+ <em:maxVersion>39.0</em:maxVersion>
+</Description>
+</em:targetApplication>
+
+
+ </Description>
+
+</RDF>
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/lib/break.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/break.js
new file mode 100644
index 0000000..0bad411
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/break.js
@@ -0,0 +1,9 @@
+"use strict";
+var match = [/https?:\/\/www.break.com\/embed\/.*/];
+var inject = [
+ "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/lib/common.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/common.js
new file mode 100644
index 0000000..354f4e9
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/common.js
@@ -0,0 +1,20 @@
+// common part between all drivers.
+var prefs = require("sdk/simple-prefs").prefs;
+var inject = [],
+ style = [];
+inject = inject.concat([
+ "common.js",
+ "video-player.js"
+]);
+/*
+if (prefs.player === 1) {
+ // current player is leanBackPlayer
+ inject = [].concat([
+ "LeanBackPlayer/js.player/leanbackPlayer.js",
+ "LeanBackPlayer/js.player/leanbackPlayer.en.js",
+ ], inject);
+ style.push("LeanBackPlayer/css.player/leanbackPlayer.default.css");
+}
+*/
+exports.inject = inject;
+exports.style = style; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/lib/dailymotion.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/dailymotion.js
new file mode 100644
index 0000000..4872758
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/dailymotion.js
@@ -0,0 +1,9 @@
+"use strict";
+var match = [/https?:\/\/(www.)dailymotion.com\/embed\/video\/.*/];
+var inject = [
+ "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/lib/facebook.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/facebook.js
new file mode 100644
index 0000000..1198b28
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/facebook.js
@@ -0,0 +1,7 @@
+"use strict";
+var match = [/https?:\/\/(www\.|beta\.)?facebook.com\/(.*\/videos\/.*|video.php\?.*)/];
+var inject = [
+ "facebook.js"
+];
+exports.match = match;
+exports.inject = inject; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/lib/flashgot-YouTube.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/flashgot-YouTube.js
new file mode 100644
index 0000000..e8ca2d7
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/flashgot-YouTube.js
@@ -0,0 +1,535 @@
+/***** 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 *****/
+/* Modified By Moez Bouhlel to be used on HTML5-Video-EveryWhere */
+/* jshint laxbreak:true, maxstatements:false, evil:true, latedef:false */
+/* jshint maxdepth:4 */
+/* jshint maxcomplexity:false, -W116 */
+/* global args:false */
+"use strict";
+const {
+ Cc, Ci, Cu, components, ChromeWorker
+} = require("chrome");
+const service = require("sdk/preferences/service");
+var fg = {
+ log: (...args) => {
+ args.unshift("[FLASHGOT]");
+ dump(args.join(" ") + "\n");
+ },
+ getPref: (title, def) => service.get("flashgot." + title, def),
+ setPref: (title, val) => service.set("flashgot." + title, val)
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Public part.
+var Youtube = {
+
+ decode_signature: function (params) {
+ /* Not encoded. */
+ return params.stream.sig || "";
+ },
+ decode_signature_swap: function (a, idx) {
+ var tmp = a[0];
+ a[0] = a[idx % a.length];
+ a[idx] = tmp;
+ return a;
+ },
+
+ create_signature_decoder: function () {
+ var s = fg.getPref("media.YouTube.decode_signature_func", "");
+ if (!s) {
+ return new SignatureDecoder(Youtube.decode_signature);
+ }
+ // Fail fast: try to compile right now to check the code for
+ // syntax errors, so that we don't do all that heavy stuff for
+ // sandbox initialization only to fail later in evalInSandbox()
+ // and have an incorrect error message saying "error _calling_
+ // the function" while actually we failed to compile it.
+ var func = null;
+ try {
+ func = new Function("params", s);
+ } catch (x) {
+ throw new Error("Error compiling YouTube.decode_signature_func: " + (x.message || x));
+ }
+ if ( ! fg.getPref("media.YouTube.decode_signature_func.sandbox", true)) {
+ return new SignatureDecoder(func);
+ }
+ // Wrap the code into a function invocation because we promised
+ // to call it as a function with one parameter.
+ s = "(function(params){\n" + s + "\n})(params);";
+ return new SandboxedSignatureDecoder(s)
+ // Sandboxing stuff is not supported - fall back to non-sandboxed.
+ || new SignatureDecoder(func);
+ },
+
+
+ refresh_signature_func: function (w, callback /*= null*/, force /*= false*/) {
+ return SDASniffer.sniff(w, callback, force);
+ }
+
+}; // Youtube
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Private part.
+
+// interface ISignatureDecoder {
+// string decode(Params params);
+// void dispose();
+// }
+// class Params {
+// Map<string, string> stream;
+// Map<string, string> video_info;
+// Function swap; //Array swap(Array, int);
+// }
+//
+// class SignatureDecoder implements ISignatureDecoder {
+// SignatureDecoder(Function func);
+// }
+function SignatureDecoder(func) {
+ this.func = func;
+}
+
+SignatureDecoder.prototype = {
+ decode: function(params) { return this.func(params); },
+ dispose: function() { this.func = null; }
+};
+
+
+// class SandboxedSignatureDecoder implements ISignatureDecoder {
+// SandboxedSignatureDecoder(String code_str);
+// }
+function SandboxedSignatureDecoder(code_str) {
+ this.code_str = code_str;
+
+ this.sandbox = this.create_sandbox();
+ if ( ! this.sandbox) { return null; }
+
+} // SandboxedSignatureDecoder()
+
+
+SandboxedSignatureDecoder.prototype = {
+ // https://developer.mozilla.org/en-US/docs/Security_check_basics:
+ // The null principal (whose contract ID is @mozilla.org/nullprincipal;1)
+ // fails almost all security checks. It has no privileges and can't be
+ // accessed by anything but itself and chrome. They aren't same-origin
+ // with anything but themselves.
+ SANDBOX_PRINCIPAL: Cc["@mozilla.org/nullprincipal;1"]
+ .createInstance(Ci.nsIPrincipal),
+
+ SANDBOX_OPTIONS: {wantComponents: false, wantXHRConstructor: false},
+
+ create_sandbox: function() {
+ if (typeof Cu.Sandbox !== "function") {
+ return null;
+ }
+ var s_gecko_ver = Cc["@mozilla.org/xre/app-info;1"]
+ .getService(Ci.nsIXULAppInfo)
+ .platformVersion;
+ var gecko_ver = parseInt(s_gecko_ver);
+ // NaN, Infinity.
+ if ( ! isFinite(gecko_ver)) {
+ throw new Error("Failed to parse Gecko version: '" + s_gecko_ver + "'.");
+ }
+ if (gecko_ver >= 2) {
+ return new Cu.Sandbox(this.SANDBOX_PRINCIPAL, this.SANDBOX_OPTIONS);
+ }
+ var opts = this.SANDBOX_OPTIONS;
+ var proto = opts.hasOwnProperty("sandboxPrototype") ? opts.sandboxPrototype : {} /*FIXME: null?*/;
+ var wantXrays = opts.hasOwnProperty("wantXrays") ? opts.wantXrays : true;
+ return new Cu.Sandbox(this.SANDBOX_PRINCIPAL, proto, wantXrays);
+ },
+
+ decode: function (params) {
+ var rc = Cu.evalInSandbox(
+ "var params = " + params.toSource() + ";\n" +
+ this.code_str,
+ this.sandbox);
+
+ // No fancy return values - we expect a primitive string value.
+ // We don't silently return something that could pass for a signature.
+ // Instead, we throw - to inform the user that their decode_signature_func
+ // function is broken (anyone can make a typo) or malicious.
+ //
+ // It's OK to pass uncaught exceptions as-is because even if they have
+ // getters for properties like "message", those will be executed in the
+ // context of the sandbox (i.e. the global |this| will point to the sandbox),
+ // which is useless for malicious code anyway.
+ // Here's what am I talking about - somewhere in the sandboxed code:
+ // var x = new Error();
+ // x.__defineGetter__("message", function(){alert("pwned");});
+ // throw x;
+ // or:
+ // var x = { message: { valueOf: function(){alert("pwned");}, toString: function(){alert("pwned");} } };
+ // throw x;
+ // We could catch the exceptions here, manually sanitize them and rethrow
+ // if they're safe to use in our chrome code, but I just don't see the point
+ // in doing so because if there's a bug in the security manager, then our
+ // manual sanitization will just conceal it.
+ if (typeof (rc) === "string") { return rc; }
+ // Nulls are kinda OK.
+ if (rc === null) { return ""; }
+ // A forgotten return or outdated code that returns nonexistent stream
+ // properties? Worth a warning in either case.
+ if (rc === undefined) {
+ fg.log("WARNING: YouTube.decode_signature_func returned undefined.");
+ return "";
+ }
+ throw new Error("Invalid return value type: expected string, got " + typeof (rc));
+ }, // decode()
+
+ dispose: function () {
+ if (!this.sandbox) { return; }
+ for (var p in this.sandbox) {
+ if (this.sandbox.hasOwnProperty(p)) {
+ delete this.sandbox[p];
+ }
+ }
+ if (typeof Cu.nukeSandbox === "function") {
+ Cu.nukeSandbox(this.sandbox);
+ }
+ this.sandbox = null;
+ }
+}; // SandboxedSignatureDecoder.prototype
+
+
+
+// Signature decoding algorithm (SDA) sniffer.
+var SDASniffer = {
+ // We don't want "over 9000" workers doing the same thing when one
+ // is enough (can happen if we're restoring a session with several
+ // YouTube tabs/windows).
+ // static boolean working = false;
+ // static Array<Function> callbacks = [];
+ working: false,
+ callbacks: [],
+
+ sniff: function (w, callback /*= null*/, force /*= false*/) {
+ if (typeof(callback) !== "function") { callback = null; }
+
+ if (this.working) {
+ if (callback) { this.callbacks.push(callback); }
+ return true;
+ }
+
+ // Get the SWF player URL.
+ w = w.wrappedJSObject;
+ var swf_url;
+ var o;
+ // ytplayer.config.url
+ if (w && (o = w.ytplayer) && (o = o.config)) {
+ swf_url = o.url;
+ }
+ // yt.config_["PLAYER_CONFIG"].url
+ else if (w && (o = w.yt) && (o = o.config_) && (o = o.PLAYER_CONFIG)) {
+ swf_url = o.url;
+ }
+ if (!swf_url) { return false; }
+ fg.log("SWF URL: " + swf_url);
+
+ // Automatic update frequency is limited so that we waste less traffic
+ // and CPU cycles in case YoutubeSwf code is outdated.
+ if ( ! force) {
+ var now = Math.floor(Date.now() / 1000);
+ var min_int = fg.getPref("media.YouTube.decode_signature_func.auto.min_interval", 60);
+ var last_update = fg.getPref("media.YouTube.decode_signature_func.auto.last_update_time", 0);
+ if (min_int !== 0 && now - last_update < min_int) {
+ if ( ! fg.getPref("media.YouTube.decode_signature_func.auto.last_update_ok")) {
+ return false;
+ }
+ // We promised to be async, so we can't call back _before_ we return,
+ // hence setTimeout.
+ w.setTimeout(function(){
+ try {
+ callback();
+ } catch (x) {
+ fg.log("Callback error: " + (x.message || x) + "\n" + x.stack);
+ }
+ }, 1);
+ return true;
+ }
+ fg.setPref("media.YouTube.decode_signature_func.auto.last_update_time", now);
+ }
+
+ var st, ft;
+ var stream_ctx = {
+ file: swf_url, //.split("/").pop().replace(/\?.*$/, "").replace(/#.*$/, ""),
+ bytes: "",
+ contentLength: -1,
+ bstream: null
+ };
+ var stream_listener = {
+ onDataAvailable: function (req, ctx, stream, offset, count) {
+ stream_ctx.bstream.setInputStream(stream);
+ stream_ctx.bytes += stream_ctx.bstream.readBytes(count);
+ },
+ onStartRequest: function (req /*, ctx*/) {
+ var channel = req.QueryInterface(Ci.nsIChannel);
+ if (!((channel instanceof Ci.nsIHttpChannel)
+ && components.isSuccessCode(channel.status)
+ && channel.responseStatus === 200))
+ {
+ throw new Error("cancel"); //req.cancel(NS_BINDING_ABORTED);
+ }
+ stream_ctx.contentLength = channel.contentLength || -1;
+ fg.log("SWF content length: " + stream_ctx.contentLength);
+ stream_ctx.bstream = Cc["@mozilla.org/binaryinputstream;1"]
+ .createInstance(Ci.nsIBinaryInputStream);
+ st = Date.now();
+ },
+ onStopRequest: function (req, ctx, status) {
+ ft = Date.now();
+ stream_ctx.bstream = null;
+ // SDASniffer::sniff0 is async, so we can't simply do if (SDASniffer.working) {clean up}.
+ var cleanup = true;
+ if (components.isSuccessCode(status)) {
+ fg.log("SWF downloaded in " + (ft - st) + " ms, size: " + stream_ctx.bytes.length);
+ if (stream_ctx.contentLength === -1 || stream_ctx.bytes.length === stream_ctx.contentLength) {
+ SDASniffer.sniff0(stream_ctx, callback);
+ cleanup = false;
+ }
+ else {
+ fg.log("SWF content length mismatch: expected " + stream_ctx.contentLength + ", got " + stream_ctx.bytes.length);
+ }
+ }
+ else {
+ fg.log("Failed to download the SWF: status=" + status);
+ }
+ stream_ctx = null;
+ if (cleanup) {
+ SDASniffer.working = false;
+ SDASniffer.callbacks = [];
+ }
+ }
+ }; // stream_listener
+ Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService)
+ .newChannel(swf_url, null, null)
+ .asyncOpen(stream_listener, null);
+
+ this.working = true;
+ if (callback) { this.callbacks.push(callback); }
+ fg.setPref("media.YouTube.decode_signature_func.auto.last_update_ok", false);
+ return true;
+ },
+
+
+ sniff0: function (ctx, callback) {
+ // Using a worker instead of a direct call resolves the problem
+ // with GUI freezing due to severe performance degradation: 100 ms
+ // vs 2400 ms for zip_inflate(), 100 ms vs 800 ms for swf_parse().
+ // See bug 911570 (https://bugzilla.mozilla.org/show_bug.cgi?id=911570),
+ // or 776798, or 907201, or whatever is causing it.
+ var worker = new SDAWorker( {bytes: ctx.bytes, file: ctx.file} );
+ ctx.bytes = null;
+
+ worker.onfinish = function(rc) {
+ SDASniffer.working = false;
+ var callbacks = SDASniffer.callbacks;
+ SDASniffer.callbacks = [];
+
+ if (typeof(rc) === "string") {
+ fg.log("Error refreshing signature function: " + rc);
+ return;
+ }
+
+ if ( ! rc) { return; }
+ fg.setPref("media.YouTube.decode_signature_func.auto.last_update_ok", true);
+
+ if (rc.timestamp !== fg.getPref("media.YouTube.decode_signature_func.timestamp")) {
+ fg.log("New timestamp: " + rc.timestamp);
+ fg.setPref("media.YouTube.decode_signature_func.timestamp", rc.timestamp);
+ }
+
+ if (rc.func_text !== fg.getPref("media.YouTube.decode_signature_func")) {
+ fg.log("New signature function:\n" + rc.func_text);
+ fg.setPref("media.YouTube.decode_signature_func", rc.func_text);
+ callbacks.forEach(function(f){
+ try {
+ f();
+ } catch (x) {
+ fg.log("Callback error: " + (x.message || x) + "\n" + x.stack);
+ }
+ });
+ }
+ };
+
+ try {
+ worker.start();
+ } catch (x) {
+ worker.onfinish("Error starting the worker: " + (x.message || x) + "\n" + x.stack);
+ }
+ }
+}; // SDASniffer
+
+
+
+// class SDAWorker;
+function SDAWorker(ctx) {
+ this.ctx = ctx;
+ this.worker = null;
+ this.fired_onfinish = false;
+}
+
+SDAWorker.prototype = {
+ // public
+ start: function() {
+ var worker = this.worker = new Worker("YoutubeSwf.js");
+ worker["SDAWorker::this"] = this;
+ worker.onmessage = this.worker_onmessage;
+ worker.onerror = this.worker_onerror;
+ worker.postMessage(this.ctx);
+ this.ctx = null;
+ },
+
+ // Completion event handler, implemented by the caller.
+ // void onfinish(Object data);
+ // @param data - the result of the decoding, one of:
+ // 1) a primitive string value (typeof data === "string") - there was
+ // an uncaught exception in the worker, and |data| is the error message.
+ // 2) Object - struct { string func_text; int timestamp; } - the result
+ // of the decoding. Can be null/undefined (data == null covers both)
+ // if the signature function could not be decoded.
+ onfinish: function(){},
+
+
+ // private
+ fire_onfinish: function(data) {
+ this.fired_onfinish = true;
+ try {
+ this.onfinish(data);
+ } catch (x) {
+ fg.log("Error in onfinish: " + (x.message || x) + "\n" + x.stack);
+ }
+ },
+
+ worker_onmessage: function(evt) {
+ var This = this["SDAWorker::this"];
+ // struct msg { string type; Object data; };
+ var msg = evt.data;
+ if (msg == null) {
+ fg.log("SDAWorker: Invalid message: null or undefined: " + msg);
+ This.finish();
+ return;
+ }
+ if (typeof(msg) !== "object") {
+ fg.log("SDAWorker: Invalid message: expected [object], got [" + typeof(msg) + "]: " + msg);
+ This.finish();
+ return;
+ }
+ switch (msg.type) {
+ case "done":
+ This.finish();
+ return;
+ case "log":
+ fg.log(msg.data);
+ return;
+ case "result":
+ This.fire_onfinish(msg.data);
+ return;
+ }
+ fg.log("SDAWorker: Invalid message type: '" + msg.type + "'");
+ This.finish();
+ },
+
+ worker_onerror: function(evt) {
+ var This = this["SDAWorker::this"];
+ This.fire_onfinish("Uncaught exception in worker: " + evt.message);
+ This.finish();
+ },
+
+ finish: function() {
+ if ( ! this.fired_onfinish) {
+ this.fire_onfinish(null);
+ }
+ try {
+ this.worker.terminate();
+ this.worker["SDAWorker::this"]
+ = this.worker.onmessage
+ = this.worker.onerror
+ = null;
+ this.worker = null;
+ } catch (x) {
+ fg.log("Error terminating the worker: " + (x.message || x) + "\n" + x.stack);
+ }
+ }
+}; // SDAWorker.prototype
+
+
+Youtube.fix_signature = function(data, fmts, swf_url, cb) {
+ try {
+ this.create_sig_decoder(swf_url, (signature_decoder) => {
+ for (let itag in fmts) {
+ if (fmts[itag].url.search("signature=") > 0)
+ continue;
+ fg.log("fixing stream", itag);
+ try {
+ var sig = signature_decoder.decode({
+ stream: fmts[itag],
+ video_info: data,
+ swap: this.decode_signature_swap
+ });
+ if (sig) {
+ fg.log("Fmt", itag, "url fixed:", sig);
+ fmts[itag].url += "&signature=" + encodeURIComponent(sig);
+ if(!sig.match(/^[0-9A-Z]{40}\.[0-9A-Z]{40}$/))
+ fg.setPref("media.YouTube.decode_signature_func", "");
+ } else {
+ fg.log("Failed to fix fmt", itag, "signature");
+ delete fmts[itag];
+ }
+ } catch (x) {
+ fg.log("Error calling YouTube.decode_signature_func: " + (x.message || x) + "\n" + x.stack);
+ }
+ }
+ try {
+ signature_decoder.dispose();
+ } catch (e) { /* TODO: fix it */ }
+ cb(fmts);
+ });
+ } catch (x) {
+ fg.log("Error creating signature decoder: " + (x.message || x) + "\n" + x.stack);
+ cb({});
+ }
+};
+Youtube.create_sig_decoder = function (swf_url, cb) {
+ // Wrapper around create_sig_decoder with callback and
+ // refresh_signature_decoder and emulate w object
+ if (fg.getPref("media.YouTube.decode_signature_func", "")) {
+ cb(this.create_signature_decoder());
+ } else {
+ var w = {wrappedJSObject: {ytplayer: {config: {url: swf_url}}}};
+ var success = this.refresh_signature_func(w, () => {
+ cb(this.create_signature_decoder());
+ }, true);
+ if (!success)
+ cb(this.create_signature_decoder());
+ }
+};
+SDAWorker.prototype.start = function() {
+ var worker = this.worker = new ChromeWorker(require("sdk/self").data.url("flashgot-YouTubeSwf.js"));
+ worker["SDAWorker::this"] = this;
+ worker.onmessage = this.worker_onmessage;
+ worker.onerror = this.worker_onerror;
+ worker.postMessage(this.ctx);
+ this.ctx = null;
+};
+
+exports.flashgot = Youtube;
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/lib/metacafe.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/metacafe.js
new file mode 100644
index 0000000..4529ab7
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/metacafe.js
@@ -0,0 +1,11 @@
+"use strict";
+var match = [/https?:\/\/www.metacafe.com\/watch\/.*/,
+ /https?:\/\/www.metacafe.com\/[^\/]+\/?/
+];
+var inject = [
+ "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/lib/vimeo.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/vimeo.js
new file mode 100644
index 0000000..59acc9e
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/vimeo.js
@@ -0,0 +1,11 @@
+"use strict";
+var when = "start";
+var match = [/https?:\/\/vimeo.com\/.+/,
+ /https?:\/\/player.vimeo.com\/video.*/
+];
+var inject = [
+ "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/lib/youtube.js b/data/extensions/html5-video-everywhere@lejenome.me/lib/youtube.js
new file mode 100644
index 0000000..e655ab2
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/lib/youtube.js
@@ -0,0 +1,30 @@
+"use strict";
+const flashgot = require("./flashgot-YouTube").flashgot;
+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", "*.www.youtube-nocookie.com"];
+var inject = [
+ "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/];
+var listen = {
+ "fix_signature": function(obj, worker) {
+ flashgot.fix_signature(obj.data, obj.fmts, obj.swf_url, (fmts) =>
+ worker.port.emit("fixed_signature", fmts)
+ );
+ }
+};
+exports.when = when;
+exports.match = match;
+exports.inject = inject;
+exports.redirect = redirect;
+exports.block = block;
+exports.listen = listen;
+//exports.style = []; \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/package.json b/data/extensions/html5-video-everywhere@lejenome.me/package.json
new file mode 100644
index 0000000..28f7b8a
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/package.json
@@ -0,0 +1,311 @@
+{
+ "title": "HTML5 Video Everywhere!",
+ "name": "html5-video-everywhere",
+ "id": "html5-video-everywhere@lejenome.me",
+ "version": "0.3.3",
+ "description": "Replace video player with Firefox native video player",
+ "main": "index.js",
+ "author": "Moez Bouhlel <bmoez.j@gmail.com> (http://lejenome.github.io/)",
+ "homepage": "https://github.com/lejenome/html5-video-everywhere",
+ "engines": {
+ "firefox": ">=38.0a1",
+ "fennec": ">=38.0a1"
+ },
+ "license": "MPL-2.0",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/lejenome/html5-video-everywhere.git"
+ },
+ "keywords": [
+ "firefox",
+ "android",
+ "fennec",
+ "jetpack",
+ "jpm",
+ "add-on"
+ ],
+ "devDependencies": {
+ "jpm": "lastest"
+ },
+ "permissions": {
+ "private-browsing": true,
+ "multiprocess": true
+ },
+ "preferences": [
+ {
+ "name": "autoNext",
+ "title": "Auto play next",
+ "description": "Auto play the next Video on playlist",
+ "type": "bool",
+ "value": true
+ },
+ {
+ "name": "genYTSign",
+ "title": "Decode YouTube Signature",
+ "description": "Extract YouTube signature decoder from their video player, and use it to decode signatures",
+ "type": "bool",
+ "value": true
+ },
+ {
+ "name": "lang",
+ "title": "Subtitles",
+ "description": "Select Subtitles language if available",
+ "type": "menulist",
+ "value": 0,
+ "options": [
+ {
+ "label": "None",
+ "value": "0"
+ },
+ {
+ "label": "Af",
+ "value": "1"
+ },
+ {
+ "label": "Ar",
+ "value": "2"
+ },
+ {
+ "label": "Bn",
+ "value": "3"
+ },
+ {
+ "label": "De",
+ "value": "4"
+ },
+ {
+ "label": "En",
+ "value": "5"
+ },
+ {
+ "label": "Es",
+ "value": "6"
+ },
+ {
+ "label": "Fi",
+ "value": "7"
+ },
+ {
+ "label": "Fr",
+ "value": "8"
+ },
+ {
+ "label": "Hi",
+ "value": "9"
+ },
+ {
+ "label": "Id",
+ "value": "10"
+ },
+ {
+ "label": "Is",
+ "value": "11"
+ },
+ {
+ "label": "It",
+ "value": "12"
+ },
+ {
+ "label": "Ja",
+ "value": "13"
+ },
+ {
+ "label": "Ko",
+ "value": "14"
+ },
+ {
+ "label": "Pt",
+ "value": "15"
+ },
+ {
+ "label": "Ru",
+ "value": "16"
+ },
+ {
+ "label": "Tu",
+ "value": "17"
+ },
+ {
+ "label": "Zh",
+ "value": "18"
+ }
+ ]
+ },
+ {
+ "name": "prefCdc",
+ "title": "Preferred Codec",
+ "type": "menulist",
+ "value": 0,
+ "options": [
+ {
+ "label": "WebM",
+ "value": "0"
+ },
+ {
+ "label": "Mp4",
+ "value": "1"
+ }
+ ]
+ },
+ {
+ "name": "prefQlt",
+ "title": "Preferred Quality",
+ "type": "menulist",
+ "value": 2,
+ "options": [
+ {
+ "label": "Higher",
+ "value": "0"
+ },
+ {
+ "label": "High",
+ "value": "1"
+ },
+ {
+ "label": "Medium",
+ "value": "2"
+ },
+ {
+ "label": "Low",
+ "value": "3"
+ }
+ ]
+ },
+ {
+ "name": "autoplay",
+ "title": "Auto Play Video",
+ "description": "Change default behaviour of the video player of the website",
+ "type": "menulist",
+ "value": 2,
+ "options": [
+ {
+ "label": "Default",
+ "value": "2"
+ },
+ {
+ "label": "Enabled",
+ "value": "1"
+ },
+ {
+ "label": "Disabled",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "preload",
+ "title": "Preload Video",
+ "description": "Change default behaviour of the video player of the website in case it does not auto play the video",
+ "type": "menulist",
+ "value": 2,
+ "options": [
+ {
+ "label": "Default",
+ "value": "2"
+ },
+ {
+ "label": "Enabled",
+ "value": "1"
+ },
+ {
+ "label": "Disabled",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "loop",
+ "title": "Auto Loop Video",
+ "type": "menulist",
+ "value": 2,
+ "options": [
+ {
+ "label": "Default",
+ "value": "2"
+ },
+ {
+ "label": "Always",
+ "value": "1"
+ },
+ {
+ "label": "Never",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "volume",
+ "title": "Volume",
+ "type": "integer",
+ "value": 100
+ },
+ {
+ "name": "player",
+ "title": "Video Player",
+ "description": "Set video player to use",
+ "type": "menulist",
+ "value": 0,
+ "options": [
+ {
+ "label": "Firefox Video Player",
+ "value": "0"
+ },
+ {
+ "label": "Lean Back Player",
+ "value": "1"
+ }
+ ],
+ "hidden": true
+ },
+ {
+ "name": "disableEmbed",
+ "title": "Disable for Embed Youtube",
+ "description": "Use default video player for embed videos",
+ "type": "bool",
+ "value": false,
+ "hidden": true
+ },
+ {
+ "name": "disablebreak",
+ "title": "Disable on Break",
+ "description": "Use default video player on Break",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "name": "disabledailymotion",
+ "title": "Disable on Dailymotion",
+ "description": "Use default video player on Dailymotion",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "name": "disablefacebook",
+ "title": "Disable on Facebook",
+ "description": "Use default video player on Facebook",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "name": "disablemetacafe",
+ "title": "Disable on Metacafe",
+ "description": "Use default video player on Metacafe",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "name": "disablevimeo",
+ "title": "Disable on Vimeo",
+ "description": "Use default video player on Vimeo",
+ "type": "bool",
+ "value": false
+ },
+ {
+ "name": "disableyoutube",
+ "title": "Disable on Youtube",
+ "description": "Use default video player on Youtube",
+ "type": "bool",
+ "value": false
+ }
+ ]
+} \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/break.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/break.md
new file mode 100644
index 0000000..21d8540
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/break.md
@@ -0,0 +1,5 @@
+**Milestone:**
+[Break Support](https://github.com/lejenome/html5-video-everywhere/milestones/Break%20Support)
+
+**URL:**
+- [X] `break.com/embed/<VIDEO_ID>`
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/dailymotion.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/dailymotion.md
new file mode 100644
index 0000000..cdbddd7
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/dailymotion.md
@@ -0,0 +1,5 @@
+**Milestone:**
+[Dailymotion Support](https://github.com/lejenome/html5-video-everywhere/milestones/Dailymotion%20Support)
+
+**URL:**
+- [x] `www.dailymotion.com/embed/video/<VIDEO_ID>`
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/facebook.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/facebook.md
new file mode 100644
index 0000000..1c84156
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/facebook.md
@@ -0,0 +1,11 @@
+**Milestone:**
+[Facebook Support](https://github.com/lejenome/html5-video-everywhere/milestones/Facebook%20Support)
+
+**URL:**
+- [x] `facebook.com/video?v=<VIDEO_ID>`
+- [x] `www.facebook.com/video?v=<VIDEO_ID>`
+- [x] `beta.facebook.com/video?v=<VIDEO_ID>`
+- [x] `facebook.com/<USERNAME>/videos/<VIDEO_ID>`
+
+**IN PAGE EVENTS:**
+- [ ] showing a video on the PhotoViewer dialog
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/metacafe.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/metacafe.md
new file mode 100644
index 0000000..192ee8b
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/metacafe.md
@@ -0,0 +1,10 @@
+**Milestone:**
+[Metacafe Support](https://github.com/lejenome/html5-video-everywhere/milestones/Metacafe%20Support)
+
+**URL:**
+- [x] `metacafe.com/watch/<VIDEO_ID>/<TITLE>`
+- [x] `metacafe.com/<CHANNEL_NAME>` #6
+
+**SWF:**
+- [ ] `s.mcstatic.com/Flash/vp/mc/Portal_4.0.2.5.swf`
+- [ ] `metacafe.com/fplayer/<VIDEO_ID>/<TITLE>.swf`
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/vimeo.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/vimeo.md
new file mode 100644
index 0000000..c98f266
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/vimeo.md
@@ -0,0 +1,15 @@
+**Milestone:**
+[Vimeo Support](https://github.com/lejenome/html5-video-everywhere/milestones/Vimeo%20Support)
+
+**URL:**
+- [x] `vimeo.com/channels/<CHANNEL_NAME>`
+- [x] `player.vimeo.com/video/<VIDEO_ID>`
+- [x] `vimeo.com/<VIDEO_ID>`
+- [x] `vimeo.com/<USER>`
+- [ ] `vimeo.com/couchmode/user<USER_ID>/videos/sort:<SORT_TYPE>/<VIDEO_ID>` #4
+
+**SWF:**
+- [ ] `vimeo.com/moogaloop.swf?clip_id=<VIDEO_ID>` (Flash player used by Facebook) #5
+
+**API:**
+more @ player.vimeo.com/playground
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/spec/youtube.md b/data/extensions/html5-video-everywhere@lejenome.me/spec/youtube.md
new file mode 100644
index 0000000..51eb015
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/spec/youtube.md
@@ -0,0 +1,27 @@
+**Milestone:**
+[YouTube Support](https://github.com/lejenome/html5-video-everywhere/milestones/YouTube%20Support)
+
+**URL:**
+- [x] `www.youtube.com/v/<VIDEO_ID>`
+- [x] `www.youtube.com/watch?v=<VIDEO_ID>`
+- [x] `www.youtube.com/embed/<VIDEO_ID>`
+- [ ] `www.youtube.com/apiplayer?video_id=<VIDEO_ID>&version=3` #2
+- [ ] `www.youtube.com/embed?listType=playlist&list=PL<PLAYLIST_ID>` #3
+- [ ] `www.youtube.com/embed?listType=user_uploads&list=<USERNAME>` #3
+- [ ] `www.youtube.com/embed?listType=search&list=<QUERY>` #3
+
+**QUERY:**
+- [x] autoplay 1,0
+- [ ] autohide 0,1,2
+- [ ] color
+- [ ] controls 0,1,2
+- [ ] enablejsapi 0,1
+- [ ] end
+- [ ] fs 0,1
+- [x] loop 0,1
+- [ ] playlist
+- [x] start
+- [x] t
+
+**API:**
+more @ https://developers.google.com/youtube/player_parameters
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/test/test-main.js b/data/extensions/html5-video-everywhere@lejenome.me/test/test-main.js
new file mode 100644
index 0000000..dd8fb7e
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/test/test-main.js
@@ -0,0 +1,13 @@
+"use strict";
+var main = require("./main");
+
+exports["test main"] = function(assert) {
+ assert.pass("Unit test running!");
+};
+
+exports["test main async"] = function(assert, done) {
+ assert.pass("async Unit test running!");
+ done();
+};
+
+require("sdk/test").run(exports); \ No newline at end of file
diff --git a/data/extensions/html5-video-everywhere@lejenome.me/test/test.html b/data/extensions/html5-video-everywhere@lejenome.me/test/test.html
new file mode 100644
index 0000000..4480a41
--- /dev/null
+++ b/data/extensions/html5-video-everywhere@lejenome.me/test/test.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>HTML5 Video EveryWhere Manual Test</title>
+ <script>
+ document.addEventListener("DOMContentLoaded", function() {
+ document.getElementById("testUrls").onclick = function(e) {
+ if(e.currentTarget !== e.target && e.target.dataset.url){
+ document.getElementById("testFrame").src = e.target.dataset.url;
+ e.target.style.backgroundColor = "green";
+ }
+ };
+ });
+ </script>
+ <style>
+ body {height: 100%; width: 100%}
+ #testUrls a { border: black solid 1px; margin: 2px;}
+ #testFrame {width: 100%; min-height: 400px}
+ </style>
+</head>
+<body>
+ <div id="testUrls">
+ <a data-url="https://youtube.com/watch?v=ltun92DfnPY&amp;list=FLem-lx9iHZGg5LOrNPJ9Peg&amp;index=3">YT /watch</a>
+ <a data-url="https://youtube.com/embed/2sTt-51iS_I">YT /embed</a>
+ <a data-url="https://youtube.com/user/WatchMojo">YT /user</a>
+ <a data-url="https://facebook.com/video.php?v=10153178235822275">FB /video</a>
+ <a data-url="https://vimeo.com/channels/documentaryfilm">Vimeo /channel</a>
+ <a data-url="https://vimeo.com/channels/staffpicks/117128919">Vimeo /channel/X/Y</a>
+ <a data-url="https://vimeo.com/groups/filmschool/videos/100175238">Vimeo /groups/X/videos/Y</a>
+ <a data-url="https://vimeo.com/86877247">Vimeo /VIDEO</a>
+ <a data-url="https://vimeo.com/focuspulling">Vimeo /USER</a>
+ <a data-url="https://metacafe.com/watch/11371672/everything_wrong_with_underworld_evolution/">metacafe /watch/X/Y</a>
+ <a data-url="https://metacafe.com/watch/cb-lJ6KDvO07Aab/marcus_smart_shoves_a_texas_tech_fan/">metacafe /watch/X/Y</a>
+ <a data-url="https://dailymotion.com/embed/video/x2eqonv_impossible-sellotape_tech">dailymotion /embed/video</a>
+ <a data-url="https://break.com/embed/2810311">Break /embed</a>
+ </div>
+ <iframe id="testFrame">
+ </iframe>
+
+</body>
+</html>