| Index: safari/include.youtube.js | 
| =================================================================== | 
| --- a/safari/include.youtube.js | 
| +++ b/safari/include.youtube.js | 
| @@ -22,11 +22,13 @@ | 
| if (!ext.backgroundPage.sendMessageSync({type: "get-domain-enabled-state"}).enabled) | 
| return; | 
|  | 
| +  var badArgumentsRegex = /^((.*_)?(ad|ads|afv|adsense)(_.*)?|(ad3|st)_module|prerolls|interstitial|infringe|iv_cta_url)$/; | 
| + | 
| function rewriteFlashvars(flashvars) | 
| { | 
| var pairs = flashvars.split("&"); | 
| for (var i = 0; i < pairs.length; i++) | 
| -      if (/^((ad|afv|adsense)(_.*)?|(ad3|st)_module|prerolls|interstitial|infringe|iv_cta_url)=/.test(pairs[i])) | 
| +      if (badArgumentsRegex.test(pairs[i].split("=")[0])) | 
| pairs.splice(i--, 1); | 
| return pairs.join("&"); | 
| } | 
| @@ -66,21 +68,98 @@ | 
| player.parentNode.replaceChild(newPlayer, player); | 
| } | 
|  | 
| +  function runInPage(fn, arg) | 
| +  { | 
| +    var script = document.createElement("script"); | 
| +    script.type = "application/javascript"; | 
| +    script.async = false; | 
| +    script.textContent = "(" + fn + ")(" + arg + ");"; | 
| +    document.documentElement.appendChild(script); | 
| +    document.documentElement.removeChild(script); | 
| +  } | 
| + | 
| document.addEventListener("beforeload", function(event) | 
| { | 
| if ((event.target.localName == "object" || event.target.localName == "embed") && /:\/\/[^\/]*\.ytimg\.com\//.test(event.url)) | 
| patchPlayer(event.target); | 
| }, true); | 
|  | 
| -  // if history.pushState is available, YouTube uses the history API | 
| -  // when navigation from one video to another, and tells the flash | 
| -  // player with JavaScript which video and which ads to show next, | 
| -  // bypassing our flashvars rewrite code. So we disable | 
| -  // history.pushState before YouTube's JavaScript runs. | 
| -  var script = document.createElement("script"); | 
| -  script.type = "application/javascript"; | 
| -  script.async = false; | 
| -  script.textContent = "History.prototype.pushState = undefined;"; | 
| -  document.documentElement.appendChild(script); | 
| -  document.documentElement.removeChild(script); | 
| +  runInPage(function(badArgumentsRegex) | 
| +  { | 
| +    // If history.pushState is available, YouTube uses the history API | 
| +    // when navigation from one video to another, and tells the flash | 
| +    // player with JavaScript which video and which ads to show next, | 
| +    // bypassing our flashvars rewrite code. So we disable | 
| +    // history.pushState before YouTube's JavaScript runs. | 
| +    History.prototype.pushState = undefined; | 
| + | 
| +    // The HTML5 player is configured via ytplayer.config.args. We have | 
| +    // to make sure that ad-related arguments are ignored as they are set. | 
| +    var ytplayer = undefined; | 
| +    Object.defineProperty(window, "ytplayer", | 
| +    { | 
| +      configurable: true, | 
| +      get: function() | 
| +      { | 
| +        return ytplayer; | 
| +      }, | 
| +      set: function(rawYtplayer) | 
| +      { | 
| +        if (!rawYtplayer || typeof rawYtplayer != "object") | 
| +        { | 
| +          ytplayer = rawYtplayer; | 
| +          return; | 
| +        } | 
| + | 
| +        var config = undefined; | 
| +        ytplayer = Object.create(rawYtplayer, { | 
| +          config: { | 
| +            enumerable: true, | 
| +            get: function() | 
| +            { | 
| +              return config; | 
| +            }, | 
| +            set: function(rawConfig) | 
| +            { | 
| +              if (!rawConfig || typeof rawConfig != "object") | 
| +              { | 
| +                config = rawConfig; | 
| +                return; | 
| +              } | 
| + | 
| +              var args = undefined; | 
| +              config = Object.create(rawConfig, { | 
| +                args: { | 
| +                  enumerable: true, | 
| +                  get: function() | 
| +                  { | 
| +                    return args; | 
| +                  }, | 
| +                  set: function(rawArgs) | 
| +                  { | 
| +                    if (!rawArgs || typeof rawArgs != "object") | 
| +                    { | 
| +                      args = rawArgs; | 
| +                      return; | 
| +                    } | 
| + | 
| +                    args = {}; | 
| +                    for (var arg in rawArgs) | 
| +                    { | 
| +                      if (!badArgumentsRegex.test(arg)) | 
| +                        args[arg] = rawArgs[arg]; | 
| +                    } | 
| +                  } | 
| +                } | 
| +              }); | 
| + | 
| +              config.args = rawConfig.args; | 
| +            } | 
| +          } | 
| +        }); | 
| + | 
| +        ytplayer.config = rawYtplayer.config; | 
| +      } | 
| +    }); | 
| +  }, badArgumentsRegex); | 
| })(); | 
|  |