289 lines
19 KiB
JavaScript
289 lines
19 KiB
JavaScript
"use strict";
|
|
|
|
function registerHandlers(handlers, TRACE, isHandlingUserInput, setHandlingUserInput, lastUserInput, data = {})
|
|
{
|
|
var dummyid = Math.floor(Math.random() * 100);
|
|
|
|
function testUserInput(el, delay)
|
|
{
|
|
var win = el.ownerDocument.defaultView, _last = lastUserInput(win), e = _last && _last.e;
|
|
if (!e || Date.now() - _last.time > delay) return false;
|
|
var px = e.pageX - win.scrollX, py = win.scrollY ? e.pageY - win.scrollY : e.clientY, r = el.getBoundingClientRect(), {width ,height} = r;
|
|
for (var i = 0; i < 5 && el.parentNode && (r.top + win.scrollY < 0 || r.left + win.scrollX < 0 || r.width < 10 || r.height < 10); i++) r = (el = el.parentNode).getBoundingClientRect();
|
|
r.width = Math.max(r.width, width), r.height = Math.max(r.height, height);
|
|
return px >= r.left && px <= r.right && py >= r.top && py <= r.bottom;
|
|
};
|
|
// htmlmedia
|
|
handlers.add(function handleHtmlMedia(aElement){
|
|
|
|
const simEvents = {play: 0, playing: 50, pause: 350}, eventTypes = Object.keys(simEvents), props = ["preload","autoplay","poster","setAttribute","removeAttribute"];
|
|
const document = aElement.ownerDocument, window = document.defaultView;
|
|
if (aElement.localName == "video" || aElement.localName == "audio")
|
|
{
|
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
|
TRACE('handleElement html5 media - tag: %s id: %s autoplay: %s preload: "%s" poster: %s paused: %s')(aElement.localName, aElement.id, aElement.autoplay, aElement.preload, !!aElement.poster, aElement.paused);
|
|
if (aElement.wrappedJSObject.play !== window.wrappedJSObject.HTMLMediaElement.prototype.play) TRACE('handleElement html5 media - %s.play() != HTMLMediaElement.play !!!')(aElement.id);
|
|
// Yendifplayer .autoplay = 1 => ...
|
|
var autoplay = aElement.autoplay || !aElement.paused, count = 0, released = false;
|
|
Object.defineProperties(aElement.wrappedJSObject, { preload: {configurable: true, set: (a) => TRACE('%s.preload = "%s"')(aElement.id, a)/* || (aElement.preload = "metadata")*/, get: () => aElement.preload}
|
|
, autoplay: {configurable: true, set: (a) => TRACE("%s.autoplay = %s")(aElement.id, a) || (a && aElement.wrappedJSObject.play()), get: () => aElement.autoplay}});
|
|
aElement.wrappedJSObject.setAttribute = (a, b) => (props.indexOf(a) != -1) ? TRACE("%s.setAttribute(%s, %s)")(aElement.id, a, b) || (aElement.wrappedJSObject[a] = b): aElement.setAttribute(a, b);
|
|
aElement.wrappedJSObject.removeAttribute = (a) => (props.indexOf(a) != -1) ? TRACE("%s.removeAttribute(%s)")(aElement.id, a) : aElement.removeAttribute(a);
|
|
|
|
function simPlay(e) {
|
|
e && aElement.removeEventListener(e.type, simPlay);
|
|
if (aElement.simPlay !== false && aElement.paused)
|
|
eventTypes.forEach((key) => window.setTimeout(() => !released && (TRACE("simPlay - %s.%s")(aElement.id, key) || aElement.dispatchEvent(new window.Event(key))), simEvents[key]));
|
|
};
|
|
|
|
aElement.wrappedJSObject.play = () => {
|
|
var force = aElement.allowPlay || testUserInput(aElement, 5000);
|
|
var userInput = isHandlingUserInput(window);
|
|
TRACE("%s.play(%s) - force: %s state: %s user: %s")(aElement.id, count, !!force, aElement.readyState, userInput);
|
|
if (!userInput && !force) {
|
|
count++ == 0 && (aElement.preload = "metadata") && (aElement.simPlay || aElement.readyState >= 2 ? simPlay() : aElement.addEventListener("loadeddata", simPlay));
|
|
return count < 5 ? Promise.reject(new window.DOMException("The play method is not allowed by the user agent.", "NotAllowedError")) : simPlay() || Promise.resolve();
|
|
}
|
|
released = !data.strict && delete aElement.wrappedJSObject.play; // jwplayer: zapiks.fr rottentomatoes baeblemusic
|
|
force && !userInput && setHandlingUserInput(window);
|
|
return aElement.play();
|
|
};
|
|
window.wrappedJSObject.Object.defineProperty(aElement.wrappedJSObject.play, "toString", window.Object.assign(window.Object(), {value: () => "[native code]"}));
|
|
aElement.autoplay = false;
|
|
aElement.preload != "none" && (aElement.preload = "metadata"); // mediaelement.js
|
|
!data.strict && aElement.addEventListener("play", function cleanup(e){ e.isTrusted && !aElement.paused && (aElement.removeEventListener("play", cleanup), aElement.muted = false,
|
|
TRACE("%s cleanup...")(aElement.id), props.forEach((prop) => delete aElement.wrappedJSObject[prop]), delete aElement.wrappedJSObject.play)});
|
|
autoplay && aElement.wrappedJSObject.play(); // flowplayer
|
|
!aElement.paused ? !released && aElement.pause() : window.setTimeout(() => !released && aElement.pause(), 0); // dbtv.no html5box
|
|
};
|
|
});
|
|
// simplay
|
|
const hosts = [{host: "cnn.com$", val: true}, {host: "twitch.tv$"}, {host: "yastatic.net$"},
|
|
{host: "bbc.(com|co.uk)$"}, {host: "(yahoo|yimg).com$", class: "html5-video", val: true}, {class: "\\b(video-js|vjs-tech)\\b"}];
|
|
handlers.add(function handleSimplay(aElement){
|
|
if (aElement.localName == "video")
|
|
for (var a of hosts) if (aElement.ownerDocument.location.hostname.match(a.host) && aElement.className.match(a.class)) aElement.simPlay = !!a.val;
|
|
});
|
|
// YouTube
|
|
handlers.add(function handleYouTube(aElement){
|
|
|
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
|
if (document.location.hostname.search("\.youtube(-nocookie)?\.com$") != -1)
|
|
{
|
|
TRACE("handleElement ytplayer - tag: %s player: %s")(aElement.localName, aElement.id);
|
|
if (document.location.search.search("feature=youtube-anywhere-player") == -1)
|
|
{
|
|
function stopPlayer(ytplayer){
|
|
if (testUserInput(ytplayer, 5000)) return !TRACE("ytplayer released...")();
|
|
var vid = ytplayer.getVideoData && ytplayer.getVideoData().video_id;
|
|
TRACE("ytplayer stopPlayer(%s) - videoId: %s t: %s")(ytplayer.id || "", vid, ytplayer.getCurrentTime());
|
|
ytplayer.cueVideoById(vid, ytplayer.getCurrentTime());
|
|
var nop = false, _seekTo = ytplayer.seekTo, _playVideo = ytplayer.playVideo;
|
|
ytplayer.playVideo = function doNothing() { nop || (nop = testUserInput(ytplayer, 1000)) ? _playVideo.apply(this) : TRACE("@@@@@@ ytplayer doNothing @@@@@")()};
|
|
ytplayer.seekTo = function seekTo(tm) { nop || (nop = testUserInput(ytplayer, 1000)) ? _seekTo.apply(this, arguments) : ytplayer.cueVideoById(vid, tm), TRACE("ytplayer seekTo(%s)")(tm); };
|
|
function onstate(a) { if (a == 1) { nop = true; ytplayer.playVideo = _playVideo; ytplayer.seekTo = _seekTo; TRACE("ytplayer - removed doNothing")(); ytplayer.removeEventListener("onStateChange", onstate); }};
|
|
ytplayer.addEventListener("onStateChange", onstate);
|
|
}
|
|
if (aElement.localName == "video" && aElement.parentNode.classList.contains("html5-video-container")) {
|
|
if (!data.strict && aElement.parentNode.parentNode.id == "movie_player")
|
|
window.setTimeout(() => aElement.allowPlay = true, document.location.search.search("feature=youtube-anywhere-player") == -1 ? 5000 : 0);
|
|
aElement.simPlay = false;
|
|
if (aElement.parentNode.parentNode.classList.contains("html5-video-player"))
|
|
window.setTimeout(() => stopPlayer(aElement.wrappedJSObject.parentNode.parentNode));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
// googleads
|
|
handlers.add(function handleGoogleAds(aElement){
|
|
const document = aElement.ownerDocument, window = document.defaultView;
|
|
var host = aElement.getRootNode().host;
|
|
if (host && host.localName == "lima-video") {
|
|
TRACE("handleElement googleads - tag: %s")(aElement.localName);
|
|
window.addEventListener("visibilitychange", (e) => e.stopPropagation(), true);
|
|
aElement.wrappedJSObject.addEventListener("play", function(){ if (!testUserInput(this, 100)) this.pause()}, {once: true});
|
|
return true;
|
|
}
|
|
});
|
|
// ifunny.co
|
|
handlers.add(function handleIFunny(aElement){
|
|
const document = aElement.ownerDocument, window = document.defaultView;
|
|
if (document.location.hostname.match("ifunny.co$") && aElement.paused) {
|
|
(isHandlingUserInput(window) || testUserInput(aElement.parentNode, 1000)) ? aElement.play() : aElement.src = "";
|
|
return true;
|
|
}
|
|
});
|
|
// msn.com
|
|
handlers.add(function handleMsn(aElement){
|
|
|
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
|
if (document.location.hostname.search(/\.msn\.com$/) != -1)
|
|
{
|
|
var obj = aElement.wrappedJSObject;
|
|
if (aElement.className.indexOf("vxFlashPlayer") != -1 && aElement.localName == "embed"){
|
|
obj.MsnVideoCallback = function(msg) { msg == "playVideo" ? delete obj.MsnVideoCallback : obj.__proto__.MsnVideoCallback.apply(obj, arguments)};
|
|
var flashvars = (aElement.getAttribute("flashvars") || "").replace(/(&ap=)true/gi, "$1false")
|
|
aElement.setAttribute("flashvars", flashvars);
|
|
TRACE("handleElement msnplayer - tag: %s id: %s ")(aElement.localName, aElement.id);
|
|
return true;
|
|
}
|
|
}
|
|
});
|
|
// BBC
|
|
handlers.add(function handleBBC(aElement){
|
|
|
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
|
if (jsWin.embeddedMedia && jsWin.embeddedMedia.players)
|
|
for (var player of jsWin.embeddedMedia.players || []) if (player._swf && player._swf.id == aElement.id) {
|
|
TRACE("handleElement BBC - embeddedMedia.players id: %s autoplay: %s")(player._swf.id, player._settings.autoplay);
|
|
Object.defineProperty(player._settings, "autoplay", {get: () => false});
|
|
player.setData = (info) => ( info.data && (info.data.autoPlayFirstItem = false), player.__proto__.setData.call(player, info));
|
|
window.setTimeout(function(){ player._settings.autoplay = true; handlers.remove(window, handleBBC); }, 2500);
|
|
return true;
|
|
};
|
|
});
|
|
// metacafe
|
|
handlers.add(function handleMetacafe(aElement){
|
|
|
|
if (aElement.localName == "object" && (aElement.data || "").search(/s.mcstatic.com\/Flash\/.*\.swf/) != -1)
|
|
{
|
|
var param = aElement.querySelector("#" + aElement.id + ">param[name=flashvars]");
|
|
param.value = param.value.replace(/&beacons=.*(?=&)/,"");
|
|
var id = param.value.match(/itemID=([^&]*)(?=&)/)[1];
|
|
var data = aElement.data;
|
|
aElement.data = "http://www.metacafe.com/fplayer/" + id + "/.swf";
|
|
function onClick(aEvent){
|
|
aEvent.stopImmediatePropagation();
|
|
aElement.removeEventListener(aEvent.type, onClick, true);
|
|
aElement.data = data;
|
|
}
|
|
aElement.addEventListener("mouseup", onClick, true);
|
|
TRACE("handleElement metacafe - data: %s")(aElement.data);
|
|
return true;
|
|
}
|
|
});
|
|
// jwplayer
|
|
handlers.add(function handleJWPlayer(aElement){ // return;
|
|
|
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
|
if (jsWin.jwplayer && !aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]"))
|
|
{
|
|
if (testUserInput(aElement, 5000)) return !TRACE("jwplayer released...")();
|
|
function closest(node, selector) { while(node && !node.matches(selector)) node = node.parentElement; return node};
|
|
var res, ar, player = jsWin.jwplayer(aElement).config ?
|
|
jsWin.jwplayer(aElement) : (res = closest(aElement, ".jwplayer")) ? jsWin.jwplayer(res) : null;
|
|
|
|
if (player && (player.config || (player.config = player.getConfig())) && player.config.autostart != false)
|
|
{
|
|
TRACE("handleElement jwplayer setup - id: %s autostart: %s")(player.id, player.config.autostart);
|
|
|
|
player.config.autoStart = player.config.autostart = false;
|
|
(ar = player.config.aspectratio) && ar.indexOf("%") != -1 && (player.config.aspectratio = "100:" + ar.slice(0,-1));
|
|
aElement.localName == "video" && window.setTimeout(() => aElement.src = "");
|
|
player.setup(player.config);
|
|
}
|
|
TRACE("handleElement jwplayer - id: %s config: %s")((player && player.id), !!(player && player.config));
|
|
return player && player.config;
|
|
}
|
|
});
|
|
// flowplayer
|
|
handlers.add(function handleFlowplayer(aElement){ //return;
|
|
|
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]")
|
|
var config, flashvars = param ? param.value : aElement.getAttribute("flashvars");
|
|
if (flashvars && flashvars.search(/^config={/) != -1)
|
|
if ((config = JSON.parse(flashvars.slice(7).replace(/'/g,'"').replace(/("autoPlay":)true/g,"$1false"))) && (config.playlist || config.clip))
|
|
{
|
|
var playlist = (config.playlist = (config.playlist || [config.clip]));
|
|
(typeof playlist[0] == 'string') && (playlist[0] = {url: playlist[0]});
|
|
playlist[0].autoPlay = (typeof playlist[0].url == 'string' && playlist[0].url.search(/(.png|.jpg)/) != -1);
|
|
(playlist[0].autoBuffering && (playlist[0].autoBuffering = false)) || (playlist[0].autoPlay && playlist[1] && (playlist[1].autoPlay = false));
|
|
flashvars = "config=" + JSON.stringify(config);
|
|
param ? param.value = flashvars : aElement.setAttribute("flashvars", flashvars);
|
|
if (aElement.data) aElement.data = aElement.data;
|
|
TRACE("handleElement flowplayer - id: %s flashvars: %s")(aElement.id, flashvars);
|
|
return true;
|
|
}
|
|
});
|
|
// aol
|
|
handlers.add(function handleAol(aElement){
|
|
|
|
if (aElement.localName == "object" && (aElement.data || "").search(/cdn(-ssl)?.vidible.tv\/.*\.swf/) != -1)
|
|
{
|
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]");
|
|
if (param)
|
|
{
|
|
param.value = param.value.replace(/(initialization%22%3A%22)autoplay/, "$1click");
|
|
aElement.wrappedJSObject.doPlay = function() { TRACE("doNothing - doPlay")()};
|
|
aElement.ownerDocument.defaultView.setTimeout(() => {delete aElement.wrappedJSObject.doPlay; TRACE("handleElement aol - removed doPlay")()}, 5000);
|
|
return !TRACE("handleElement aol - data: %s")(aElement.data);
|
|
}
|
|
}
|
|
});
|
|
// general
|
|
var colValues = {"true":"false", "1":"0", "yes":"no", "on":"off", "y":"n", "Y":"N"}
|
|
function replace(match,p0,p1,p2) {
|
|
var res = p0 + (!p1 && p2 && colValues[p2] ? colValues[p2] : !!p1);
|
|
TRACE(">>> handleElement replace - match: %s p0: %s p1: %s p2: %s res: %s <<<")(match, p0, p1, p2, res);
|
|
return res;
|
|
}
|
|
function modifyParams(str) { return (str || "").replace(/((no)?auto_?(?:play|start|run)\w*(?:["']?\s?[=:]\s?["']?|%22%3A(?!\W)))(true|1|yes|y|on|null|)(?=\W|$)/gi, replace)};
|
|
|
|
function handleGeneral(aElement){
|
|
|
|
if (aElement.localName != "object" && aElement.localName != "embed")
|
|
return;
|
|
|
|
var data = modifyParams(aElement.getAttribute("data"));
|
|
if (data != aElement.getAttribute("data") && data != "")
|
|
{
|
|
aElement.setAttribute("data", data);
|
|
TRACE("handleElement - %s.data: %s")(aElement.localName, data);
|
|
}
|
|
|
|
var flashvars = modifyParams(aElement.getAttribute("flashvars")); // cnn | (remove) neulion nhl embed
|
|
if (aElement.localName == "embed" )
|
|
{
|
|
aElement.setAttribute("menu","true");
|
|
|
|
if (flashvars == aElement.getAttribute("flashvars") || flashvars == "" )
|
|
{
|
|
flashvars += "&autoplay=false&autostart=false&autoPlay=0"; // youtube(autoplay) | ustream live
|
|
aElement.setAttribute("play","false"); // basic flash
|
|
}
|
|
aElement.setAttribute("flashvars", flashvars);
|
|
if (aElement.src)
|
|
{
|
|
var src = modifyParams(aElement.src); // embed dailymotion
|
|
if (src != aElement.src) {
|
|
aElement.src = src;
|
|
var parent = aElement.parentNode, next = aElement.nextSibling; // workaround for chrome embed.src =
|
|
if (aElement.src && parent) { aElement.remove(); parent.insertBefore(aElement.wrappedJSObject, next); };
|
|
TRACE("handleElement embed.src: %s")(src);
|
|
}
|
|
}
|
|
}
|
|
|
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100)); // [id =''] works with numeric ids!!!
|
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars], [id='" + aElement.id + "']>param[name=FlashVars], [id='" + aElement.id + "']>param[name=flashVars]");
|
|
if (param)
|
|
{
|
|
flashvars = modifyParams(param.value); // ustream(autoplay=false) | bbc / metacafe.embed(no) / tv.com(vid)
|
|
if (flashvars == param.value) {
|
|
if (flashvars.search(/auto(_?play(vid)?|start|run)["']?\s?[=:]/i) != -1) return; // false already exists...
|
|
flashvars += "&autoplay=false&autoPlay=0&autoStart=0&_autoPlay=no&auto_start=off"; // justin.tv(autoPlay=0)|nba.com(autostart)|espn(!autoplay)|discovery(_autoPlay=no)|56.com(auto_start)
|
|
}
|
|
param.value = flashvars;
|
|
if (aElement.data) aElement.data = aElement.data;
|
|
}
|
|
(param = aElement.querySelector("[id='" + aElement.id + "']>param[name=play]")) && (param.value = false);
|
|
if (param && aElement.data) aElement.data = aElement.data;
|
|
TRACE("handleElement - id: %s %s.flashvars: %s")(aElement.id, aElement.localName, flashvars);
|
|
};
|
|
|
|
handlers.add(handleGeneral);
|
|
}; |