Large

YouTube prewatch, not just preview

By Michael Z Last update Apr 9, 2010 — Installed 9,171 times.

There are 12 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// -----------------------------------------------------
//
// 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, 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.
//
// -----------------------------------------------------
// Author: Michael Zangl, michael@jautis.net
// Version 1.0b5
// Created: 2009-08-03
// Updated: 2010-04-09
//
// -----------------------------------------------------
//
// ==UserScript==
// @name            Youtube prewatch
// @namespace       http://www.jautis.net/
// @version         1.0b5
// @description     Plays a preview to a video after you move your mouse over it.
// @description     Spielt eine Vorschau des Videos nachdem man die Maus darüber bewegt.
// @include         http://www.youtube.com/*
// ==/UserScript==

/**
 * preferences:
 * displayDelay  delay to display the video information after the mouse went 
 *               over an element, in ms
 * playDelay     delay to play the video after displaying its information.
 * volume        the volume the little video sould have
 * timeshift     the percentage where to start playing the little video
 */


// how long shall we wait before the tooltip is displayed
const DEFAULT_DISPLAYDELAY = 500;
//how long shall we wait before the video starts playing
const DEFAULT_PLAYDELAY= 2000;
// how loud should the mini video be
const DEFAULT_VOLUME= 50;
// where shall we start playing (in % of the video length)
const DEFAULT_TIMESHIFT= 10;
//what shall we do if there is already an other video playing?
const DEFAULT_COLLISSIONACTION= "ignore";

//how wide should the tooltip be. In pixel. default: 350px
const DEFAULT_TOOLTIPSIZE= 350;

//how big should the video be (in percent of the tooltip width (default: 34.28%)
const DEFAULT_VIDEOSIZE= 34.28;

//should we show the link to the settings?
const DEFAULT_SHOWSETTINGSLINK= true;
// shall we preload the video
const DEFAULT_PRELOAD= false;
// darkColor:lightColor
const DEFAULT_COLORTHEME= "hsl(222, 87%, 80%):hsla(212, 76%, 100%, 0.7):"

const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const DEBUG = false;

function addZeros(number) {
  var desiredLength = arguments.length > 1 ? arguments[1] : 2;
  var numberString = number + "";
  while (numberString.length < desiredLength) {
    numberString = "0" + numberString;
  }
  return numberString;
}

/**
 * runs a x-path
 * @param node the node where the path sould start.
 * @param expr the xpath as String
 * @return an array of elements that match the xpath
 * @author see MDC
 */
// Evaluate an XPath expression aExpression against a given DOM node
// or Document object (aNode), returning the results as an array
// thanks wanderingstan at morethanwarm dot mail dot com for the
// initial work.
function evaluateXPath(aNode, aExpr) {
  var xpe = new XPathEvaluator();
  var nsResolver = xpe.createNSResolver(aNode.ownerDocument == null ?
    aNode.documentElement : aNode.ownerDocument.documentElement);
  var result = xpe.evaluate(aExpr, aNode, nsResolver, 0, null);
  var found = [];
  var res;
  while (res = result.iterateNext())
    found.push(res);
  return found;
}

i18n_data = {};
i18n_data["en"] = {
  "settings" : "settings",
  "TBD":
      "-not implemented yet-",
  timeParser : function(seconds) {
    if (seconds >= 60) {
      return Math.floor(seconds / 60) + ":" 
        + addZeros(Math.round(seconds % 60)) + " minutes"
    } else if (seconds < 0.1) {
      return i18n_data["en"].numberParser(seconds * 1000) + " milliseconds";
    } else if (seconds == 1) {
      return "one second";
    } else {
      return i18n_data["en"].numberParser(seconds) + " seconds";
    }
  },
  numberParser : function(number) {
    return (Math.round(number * 100) / 100 + "")
  }
}
i18n_data["de"] = {
  "author:" :
      "Autor:",
  "duration:" :
      "Länge:",
  "published:" :
      "Veröffentlicht:",
  "prewatch settings":
      "Tooltipp Einstellungen",
  "settings" :
      "Einstellungen",
  "youtube prewatch: " 
     : "Youtube Prewatch: ",
  "unknown" :
      "unbekannt",
  "data loading":
      "Daten werden geladen.",
  "data still loading":
      "Daten werden immernoch geladen.",
  //settings
  "Timing options":
      "Zeitliche Optionen",
  "when to display the tooltip":
      "Wann die Videoinformationen angezeigt werden.",
  "display delay":
      "Anzeigeverzögerung",
  "display video information after the mouse was %t over the element": 
      "Videoinformationen anzeigen wenn die Maus %t über dem Element war.",
  "additional play delay":
      "Zusätzliche Abspielverzögerung",
  "start playing video %t after the tooltip was displayed":
      "Beginne mit dem Abspielen des Videos %t nachdem die Infos angezeigt "
    + "werden. Vorher wird nur das Vorschaubild angezeigt.",
  "Play options":
      "Abspieloptionen",
  "how to play the mini video":
      "Wie das kleine Video abgespielt werden soll.",
  "volume":
      "Lautstärke",
  "volume: %d%":
      "Lautstärke: %d%",
  "timeshift":
      "Startpositionsverschiebung",
  "start position: %d%":
      "Startposition, relativ zur Videolänge: %d%",
  "if a video is played:":
      "Wenn schon ein Video abgespielt wird",
  "no action":
      "ignorieren",
  "mute preview":
      "Vorschau stumm abspielen",
  "mute player":
      "gerade abgespieltes Video stumm schalten",
  "pause player":
      "gerade abgespieltes Video pausieren",
  "TBD":
      "-Funktion noch nicht vorhanden-",
  "About":
      "Über",
  "%s by %s":
      "%s von %s",
  "Current Version: %s":
      "Aktuelle Version: %s",
  "Language code (selected by Youtube): %s":
      "Sprachcode (von Youtube übernommen): %s.",
  "More information at the scripts %s.":
    "Mehr Informationen und Updates gibt es auf der %s des Scripts.",
  "homepage" : 
    "Webseite",
  "settings are automatically saved":
      "Einstellungen werden automatisch gespeichert.",
  "close": "Schließen",
  "start preloading the video when the tooltip is displayed":
    "Beginne mit dem Laden des Videos sobald ein Tooltipp angezeigt wird.",
  timeParser : function(seconds) {
    if (seconds >= 60) {
      return Math.floor(seconds / 60) + ":" 
        + addZeros(i18n_data["de"].numberParser(seconds % 60)) + " Minuten"
    } else if (seconds < 0.1) {
      return i18n_data["de"].numberParser(seconds * 1000) + " Millisekunden";
    } else if (seconds == 1) {
      return "eine Sekunde";
    } else {
      return i18n_data["de"].numberParser(seconds) + " Sekunden";
    }
  },
  months : ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", 
            "August", "September", "Oktober", "November", "Dezember"],
  dateParser : function(date) {
    return date.getDate() + ". " + i18n_data["de"].months[date.getMonth()]
      + " " + date.getFullYear();
  },
  numberParser : function(number) {
    return (Math.round(number * 100) / 100 + "").replace(".", ",")
  }
}

function i18n(orginal) {
  var lang = document.documentElement.getAttribute("lang");
  if (!lang || typeof i18n_data[lang] == "undefined"
        || typeof i18n_data[lang][orginal] == "undefined") {
    var text = orginal;
  } else {
    var text = i18n_data[lang][orginal];
  }
  for (var i = 1; i < arguments.length; i++) {
    if (typeof arguments[i] == "string" && text.indexOf("%s") > -1) {
      text = text.replace("%s", arguments[i]);
    } else if (typeof arguments[i] == "number" && text.indexOf("%d") > -1) {
      text = text.replace("%d", arguments[i]);
    } else if (typeof arguments[i] == "number" && text.indexOf("%t") > -1) {
      text = text.replace("%t", 
        i18n_data[lang] && typeof i18n_data[lang].timeParser == "function"
          ? i18n_data[lang].timeParser(arguments[i])
          : arguments[i] + "s");
    } else if (arguments[i] instanceof Date && text.indexOf("%y") > -1) {
      text = text.replace("%y", 
        i18n_data[lang] && typeof i18n_data[lang].dateParser == "function"
          ? i18n_data[lang].dateParser(arguments[i])
          : arguments[i].getFullYear() + "-" + addZeros(arguments[i].getMonth() + 1) 
            + "-" + addZeros(arguments[i].getDate()));
    } else {
      text += arguments[i];
    }
  }
  return text;
}



var youtubePrewatch = {
  
  defaultValues : {
    displayDelay : parseInt(DEFAULT_DISPLAYDELAY),
    playDelay: parseInt(DEFAULT_PLAYDELAY),
    volume: parseInt(DEFAULT_VOLUME),
    timeshift: parseInt(DEFAULT_TIMESHIFT),
    collissionAction: DEFAULT_COLLISSIONACTION,
    videoSize: parseInt(DEFAULT_VIDEOSIZE), // in precent
    tooltipSize: parseInt(DEFAULT_TOOLTIPSIZE),
    showSettingsLink: DEFAULT_SHOWSETTINGSLINK == true,
    preload: DEFAULT_PRELOAD == true,
    colorTheme: DEFAULT_COLORTHEME
  },
  
  unsafeWindow : typeof unsafeWindow == "undefined" ? window : unsafeWindow,
  
  getSetting: function(name) {
    if (GM_getValue) {
      return GM_getValue(name, youtubePrewatch.defaultValues[name]);
    } else {
      return youtubePrewatch.defaultValues[name];
    }
  },
  setSetting: function(name, value) {
    if (GM_setValue) {
      GM_setValue(name, value);
    }
  },

  //the id of the video that is currently displayed
  currentVideoId : "",
  /* the data of known videos.
   * videoData[vid] = {name, duration, previewImage}
   * only full elements are allowed. If an element is undefined it was not 
   * loaded, if it is null it was not compleately loaded.
   */
  videoData : {},
  //the tooltips elements
  tooltipElement : null,
  //the div for the swfobject
  tooltipVideo : null,
  //the div for the preview
  tooltipPreview : null,
  //the title text for the video
  tooltipTitleText : null,
  //the time the video lasts
  tooltipDurationTime : null,
  
  /* initializes the text */
  init: function() {
    youtubePrewatch.activateAllTooltips(document.body);
    youtubePrewatch.initNodeInsertListener();
    youtubePrewatch.initSettingsElement();
    youtubePrewatch.loadCSS();
  },
  
  debug : function(data) {
    if (!DEBUG) {
    } else if (typeof youtubePrewatch.unsafeWindow.console == "object") {
      youtubePrewatch.unsafeWindow.console.debug(data)
    } else if (GM_log) {
      GM_log(data)
    }
  },
  
  //PageFunctions
  
  activateAllTooltips : function(element) {
    var as = document.body.getElementsByTagName("a");
    Array.filter(as, function(a) {
             return a.href && /v=([-\w]+)/.exec(a.href)
         })
         .forEach(youtubePrewatch.loadTextLink);
    
  },
  
  loadTextLink : function(a) {
    var videoid = /v=([-\w]+)/.exec(a.href)[1] + "";
    evaluateXPath(a, "//*[@title]|.[@title]").forEach(function(node) {
      if (node.hasAttribute("title")) {
        //e.g. for youtubeAutoplay
        node.setAttribute("oldtitle", node.getAttribute("title"));
        node.removeAttribute("title");
      }
    })
    youtubePrewatch.registerElement(a, videoid);
  },
  
  /* unneeded
  registerYoutubeVideo : function(div) {
    var img = div.getElementsByTagName("img")[0];
    if (img && img.hasAttribute("qlicon")) {
      var id = img.getAttribute("qlicon");
      youtubePrewatch.registerElement(div, id);
      img.title = "";
    }
  },*/
  
  /* watches some YoutubeElements to be changed, e.g. ajax video lists */
  /*watchYoutubeElements : function() {
    var naviOuterDiv = document.getElementById("playnav-play-panel");
    if (!naviOuterDiv) {
      return;
    }
    function renderPlaynavHolder(holderdiv) {
      if (!holderdiv.hasAttribute("_youtubePrewatchLoaded")) {
        var divs = holderdiv.getElementsByClassName("playnav-video");
        Array.forEach(divs, youtubePrewatch.registerYoutubeVideo);
        holderdiv.setAttribute("_youtubePrewatchLoaded", "true");
      }
    }
    var holder = naviOuterDiv.getElementsByClassName("playnav-playlist-holder");
    Array.forEach(holder, renderPlaynavHolder);
    youtubePrewatch.debug(holder)
    naviOuterDiv.addEventListener("overflow", function() {
      var holder = naviOuterDiv.getElementsByClassName("playnav-playlist-holder");
      Array.forEach(holder, renderPlaynavHolder)
    }, true);
  },*/
    /**
   * @param element a HTML-Element
   * @param video the video id, an object of video data (with the id) or a 
   *              function witch returns the id or the data object.
   */
  registerElement : function(element, video) {
    var videoid = typeof video == "object" ? video.id : video;
    if (typeof videoid != "string") {
      return false;
      throw "ID is not a string";
    }
    element.addEventListener("mousemove", function() {
      youtubePrewatch.showTooltip(videoid, {});
    }, true);
  },
  
  /* Tooltip */
  tooltipInitialzed : false,
  initTooltip : function() {
    document.body.addEventListener("mousemove", youtubePrewatch.moveTooltip1, true);
    document.body.addEventListener("mousemove", youtubePrewatch.moveTooltip2, false);
    document.documentElement.addEventListener("mouseout", youtubePrewatch.checkMouseOutOfPage, false);
    document.addEventListener("blur", youtubePrewatch.checkPageBlur, false);
    youtubePrewatch.initTooltipElements();
    youtubePrewatch.tooltipElement.addEventListener("mousemove", youtubePrewatch.moveTooltipMouseOverTooltip, false);
    youtubePrewatch.tooltipInitialzed = true;
  },
  
  initTooltipElements : function() {
    if (youtubePrewatch.tooltipElement != null) {
      return;
    }
    youtubePrewatch.debug("Initialisiere Tooltipp");
    youtubePrewatch.tooltipElement = document.createElement("div");
    youtubePrewatch.tooltipElement.id = "youtubePrewatch"
    document.body.appendChild(youtubePrewatch.tooltipElement);
    
    var tooltipInner = document.createElement("div");
    tooltipInner.className = "tooltipInner"
    youtubePrewatch.tooltipElement.appendChild(tooltipInner);
    
    youtubePrewatch.tooltipVideo = document.createElement("div");
    youtubePrewatch.tooltipVideo.className = "preview";
    youtubePrewatch.tooltipVideo.id = "youtubePrewatchVideo";
    tooltipInner.appendChild(youtubePrewatch.tooltipVideo);
    
    youtubePrewatch.tooltipPreview = document.createElement("img");
    youtubePrewatch.tooltipPreview.className = "preview";
    tooltipInner.appendChild(youtubePrewatch.tooltipPreview);
    
    var ratingBg = document.createElement("div");
    ratingBg.className = "rating_gray";
    youtubePrewatch.tooltipElement.appendChild(ratingBg);
    youtubePrewatch.tooltipRating = document.createElement("div");
    youtubePrewatch.tooltipRating.className = "rating_red";
    ratingBg.appendChild(youtubePrewatch.tooltipRating);
    
    
    var b = document.createElement("b");
    youtubePrewatch.tooltipTitleText = document.createTextNode(i18n("unknown"));
    b.appendChild(youtubePrewatch.tooltipTitleText);
    tooltipInner.appendChild(b);
    
    var p = document.createElement("p");
    youtubePrewatch.tooltipDescriptionText = document.createTextNode(i18n("unknown"));
    p.appendChild(youtubePrewatch.tooltipDescriptionText);
    tooltipInner.appendChild(p);
    
    var dl = document.createElement("dl");
    tooltipInner.appendChild(dl);
    
    var dt = document.createElement("dt");
    dt.appendChild(document.createTextNode(i18n("author:")));
    dl.appendChild(dt);
    
    var dd = document.createElement("dd");
    youtubePrewatch.tooltipAuthorText = document.createTextNode(i18n("unknown"));
    dd.appendChild(youtubePrewatch.tooltipAuthorText);
    dl.appendChild(dd);
    
    var dt = document.createElement("dt");
    dt.appendChild(document.createTextNode(i18n("published:")));
    dl.appendChild(dt);
    
    var dd = document.createElement("dd");
    youtubePrewatch.tooltipPublishedText = document.createTextNode(i18n("unknown"));
    dd.appendChild(youtubePrewatch.tooltipPublishedText);
    dl.appendChild(dd);
    
    var dt = document.createElement("dt");
    dt.appendChild(document.createTextNode(i18n("duration:")));
    dl.appendChild(dt);
    
    var dd = document.createElement("dd");
    youtubePrewatch.tooltipDurationText = document.createTextNode(i18n("unknown"));
    dd.appendChild(youtubePrewatch.tooltipDurationText);
    dl.appendChild(dd);
    
  },
  
  loadCSS : function() {
    if (!youtubePrewatch.styleElement) {
      youtubePrewatch.styleElement = document.createElement("style");
      (document.getElementsByTagName("head")[0] || document.documentElement)
          .appendChild(youtubePrewatch.styleElement)
    }
    colors = (youtubePrewatch.getSetting("colorTheme") + "").split(":");
    if (!colors[0])  {colors[0] = "#aaa";}  //dark background, border
    if (!colors[1])  {colors[1] = "white";}  //light background
    if (!colors[2])  {colors[2] = "black";}  //text on dark
    if (!colors[3])  {colors[3] = "black";}  //text on light
    var width = youtubePrewatch.getSetting("tooltipSize");
    var videoWidth = Math.floor((width) * youtubePrewatch.getSetting("videoSize") / 100);
    //player sometimes does not want to hide -> move it out the screen
    youtubePrewatch.styleElement.innerHTML =
          "#youtubePrewatch {position:fixed;left:0;top:0;visibility:hidden;width:" + (width + 4) + "px;overflow:auto/*=> above flash*/;margin-left:-20000px; -moz-box-shadow: rgba(100, 100, 100, 0.6) 5px 5px 5px;z-index:1100}"
        + "#youtubePrewatch > .tooltipInner {background:" + colors[1] + ";color:" + colors[3] + ";border:2px solid " + colors[0] + ";min-height:130px;position:relative;}"
        + "#youtubePrewatch.state1,#youtubePrewatch.state2 {margin-left:0;visibility:visible;}  "
        + "#youtubePrewatch .preview {position:absolute;left:10px;top:30px;width:" + videoWidth + "px; height:" + (videoWidth * 3/4) + ";}"
        + " #youtubePrewatch dl, #youtubePrewatch p {margin: 5px 10px 5px " + (videoWidth + 20) + "px;color:inherit; padding:0;display:block}"
        + "#youtubePrewatch p {white-space:pre-line; max-height:20em; overflow:hidden;}"
        + " #youtubePrewatch b {margin: 0 0 5px " + (videoWidth + 15) + "px; padding:5px 10px 5px 5px ;display:block; background-color:" + colors[0] + ";color:" + colors[2] + "; -moz-border-radius-bottomleft:4px;}"
        + " #youtubePrewatch dt {font-weight:bold;clear:left;float:left;width:80px; overflow:hidden; margin:0;}"
        + " #youtubePrewatch dd {margin:0 0 5px 90px;padding:0;}"
        + " #youtubePrewatch.state2 img {display:none}"
        + " #youtubePrewatch.state1 #youtubePrewatchVideo {left:-20000px}"
        + " #youtubePrewatch .rating_gray {position:absolute;top:10px;left:10px;height:15px;width:75px; background:white url(http://s.ytimg.com/yt/img/master-vfl125983.png) repeat-x;background-position:-75px -411px}"
        + ".rating_red {position:absolute;background-color:rgba(200,0,0,1); background-image:inherit;height:15px;background-position:0 -411px;}"
        + "#mizSettingsOuter {position:absolute;top:0;right:0;overflow:hidden;padding-bottom:5px;display:" + (youtubePrewatch.getSetting("showSettingsLink") ? "block" : "none")+ "}"
        + "#mizSettingsContainer {background-color:" + colors[0] + ";color:" + colors[2] + "; -moz-border-radius-bottomleft:4px;list-style-type:none; -moz-box-shadow: rgba(100, 100, 100, 0.6) 3px 3px 5px;}"
        + "#mizSettingsContainer > li {padding:3px 6px;}"
        + "#mizSettingsContainer a {color:inherit;}";
  },
  
  initSettingsElement : function() {
    var container = document.getElementById("mizSettingsContainer")
    if (!container) {
      var outer = document.createElement("div");
      outer.id = "mizSettingsOuter";
      document.body.appendChild(outer);
      container = document.createElement("ul");
      container.id = "mizSettingsContainer";
      outer.appendChild(container);
    }
    
    var item = document.createElement("li");
    container.appendChild(item);
    
    var settingsA = document.createElement("a");
    settingsA.href = "javascript:;";
    settingsA.addEventListener("click", youtubePrewatch.showSettings, true);
    settingsA.appendChild(document.createTextNode(i18n("prewatch settings")))
    item.appendChild(settingsA);
  },
  
  /**
   * dynamically added nodes
   */
  initNodeInsertListener : function() {
    document.body.addEventListener("DOMNodeInserted",  function(evt) {
        youtubePrewatch.nodesInsertedLately++;
        if (youtubePrewatch.nodesInsertedLately < 50) {
          youtubePrewatch.activateAllTooltips(evt.target);
        }
        setTimeout(function() {youtubePrewatch.nodesInsertedLately--}, 1000);
      }, true);
  },
  nodesInsertedLately : 0,

  //checking if a tooltip has to be displayed; onmousemove-Listeners
  videoToDisplay : null,
  moveTooltip1 : function(evt) {
    youtubePrewatch.videoToDisplay = null;
  },
  moveTooltip2 : function(evt) {
    var data = youtubePrewatch.videoToDisplay;
    if (data == null) {
      if (youtubePrewatch.currentState != 3) {
        youtubePrewatch.currentVideoId = "";
        youtubePrewatch.showTooltip_state3();
      }
    } else if (youtubePrewatch.currentVideoId != data.id) {
      //new video => reinit
      if (youtubePrewatch.currentState != 3) {
        //stop old tooltip normal
        youtubePrewatch.showTooltip_state3();
      }
      youtubePrewatch.debug("Video changed to " + data.id);
      youtubePrewatch.currentVideoId = data.id;
      youtubePrewatch.showTooltip_state0();
    }
    if (youtubePrewatch.currentVideoId) {
      youtubePrewatch.tooltipElement.realX = evt.clientX;
      youtubePrewatch.tooltipElement.realY = evt.clientY;
      youtubePrewatch.renderTooltipPosition();
    }
  },
  //prevent video from changing / prevent tooltip from hiding
  moveTooltipMouseOverTooltip : function() {
    youtubePrewatch.videoToDisplay = {id: youtubePrewatch.currentVideoId};
  },
  checkMouseOutOfPage : function(evt) {
    if (evt.clientX < 0 || evt.clientX >= window.innerWidth
        || evt.clientY < 0 || evt.clientY >= window.innerHeight) {
      if (youtubePrewatch.currentState != 3) {
        youtubePrewatch.currentVideoId = "";
        youtubePrewatch.showTooltip_state3();
      }
    }
  },
  checkPageBlur : function(evt) {
    if (evt.target == document) {
      youtubePrewatch.currentVideoId = "";
      youtubePrewatch.showTooltip_state3();
    }
  },
  /* call it after position or size was changed */
  renderTooltipPosition : function() {
    var x = youtubePrewatch.tooltipElement.realX;
    var y = youtubePrewatch.tooltipElement.realY;
    var width = youtubePrewatch.getSetting("tooltipSize");
    youtubePrewatch.tooltipElement.style.left = 
          x > window.innerWidth - width - 30
          ? (x - width - 20) + "px"
          : (x + 20) + "px";
    youtubePrewatch.tooltipElement.style.top =
         Math.min(
           window.innerHeight - youtubePrewatch.tooltipElement.offsetHeight - 15
           , y) + "px";
  },
  
  //call every time onmousemove
  /**
   * displays a tooltip for a video
   * the function waits some time until the tooltip is displayed
   * @param id the id of the video
   * @param knownData:
   *        - name
   *        - duration (String)
   *        - previewImage (src)
   */
  showTooltip : function(id, knownData) {
    if (location.href.indexOf(id) > -1) {
      return;
    }
    if (!youtubePrewatch.tooltipInitialzed) {
      youtubePrewatch.initTooltip();
    }
    //evaluated by moveTooltip2
    youtubePrewatch.videoToDisplay = {"id" : id, "data" : knownData}
  },
  
  /*
   * tooltip states : 0 => not displayed, but prepare to display. 
   *                   1 => displayed, no video. This state loads video data if 
   *                        neccessary
   *                   2 => video mode
   *                   3 => not displayed / hidden
   */
  stateTimeout : 0,
  currentState : 3,
  /**
   * private; shows the tooltip in state 0 and starts the state 1 timer
   */
  showTooltip_state0 : function() {
    youtubePrewatch.currentState = 0;
    youtubePrewatch.debug("state 0");
    youtubePrewatch.stateTimeout = setTimeout(youtubePrewatch.showTooltip_state1,
          youtubePrewatch.getSetting("displayDelay",
            youtubePrewatch.defaultValues.displayDelay));
    youtubePrewatch.tooltipElement.className = "state0";
  },
  
  showTooltip_state1 : function() {
    youtubePrewatch.currentState = 1;
    youtubePrewatch.debug("state 1");
    //youtubePrewatch.tooltipElement.style.visibility = "visible";
    youtubePrewatch.tooltipElement.className = "state1";
    youtubePrewatch.stateTimeout = setTimeout(youtubePrewatch.showTooltip_state2,
          youtubePrewatch.getSetting("playDelay", 
            youtubePrewatch.defaultValues.playDelay));
    youtubePrewatch.displayVideoData();
  },
  
  showTooltip_state2 : function() {
    youtubePrewatch.currentState = 2;
    youtubePrewatch.debug("state 2");
    //youtubePrewatch.tooltipElement.style.visibility = "visible";
    youtubePrewatch.tooltipElement.className = "state2";
    var doMute = youtubePrewatch.pageVideoTooltipShow();
    youtubePrewatch.playVideo(youtubePrewatch.currentVideoId, doMute);
  },
  
  showTooltip_state3 : function() {
    youtubePrewatch.currentState = 3;
    youtubePrewatch.debug("state 3");
    clearTimeout(youtubePrewatch.stateTimeout);
    //youtubePrewatch.tooltipElement.style.visibility = "";
    youtubePrewatch.tooltipElement.className = "state3";
    youtubePrewatch.pageVideoTooltipHide()
    setTimeout('youtubePrewatch.stopVideo();', 0);
  },
  
  
  /* player */
  /**
   * starts playing the video with an id
   */
  playVideo : function(id, doMute) {
    youtubePrewatch.debug("Playing " + id);
    if (doMute) {
      var volume = 0;
    } else {
      var volume = youtubePrewatch.getSetting("volume");
    }
    var timeshiftPercent = youtubePrewatch.getSetting("timeshift",
        youtubePrewatch.defaultValues.timeshift);
    var timeshift = ((youtubePrewatch.videoData[id] 
          || {duration:0}).duration || 0) * timeshiftPercent / 100;
    if (!id) {
      return;
    }
    youtubePrewatch.debug("Volume " + volume + "; Start time: " + timeshift)
    setTimeout('youtubePrewatch.startVideo("' 
            + id + '", ' + timeshift + ', ' + volume + ');', 0);
  },
  
  
  displayVideoData : function() {
    var id = youtubePrewatch.currentVideoId
    if (!id) {
    } else if (typeof youtubePrewatch.videoData[id] == "undefined") {
      youtubePrewatch.tooltipTitleText.data = i18n("data loading");
      youtubePrewatch.tooltipTitleText.parentNode.className = "dataLoading";
      
      GM_xmlhttpRequest({
        method: "GET",
        url: "http://gdata.youtube.com/feeds/api/videos/" + id,
        onload: youtubePrewatch.reciveVideoData
      });
      //check if we got something
      setTimeout(function() {
        //TODO
      }, 1000);
      youtubePrewatch.videoData[id] = null;
      youtubePrewatch.displayEmptyVideoData();
    } else if (youtubePrewatch.videoData[id] === null) {
      youtubePrewatch.tooltipTitleText.data = i18n("data still loading");
      youtubePrewatch.tooltipTitleText.parentNode.className = "dataLoading";
      youtubePrewatch.displayEmptyVideoData();
    } else {
      youtubePrewatch.tooltipTitleText.parentNode.className = "";
      youtubePrewatch.tooltipTitleText.data = youtubePrewatch.videoData[id].title;
      youtubePrewatch.tooltipDescriptionText.data = youtubePrewatch.videoData[id].description;
      youtubePrewatch.tooltipAuthorText.data = youtubePrewatch.videoData[id].author;
      youtubePrewatch.tooltipPublishedText.data = i18n("%y", youtubePrewatch.videoData[id].published);
      youtubePrewatch.tooltipDurationText.data = i18n("%t", youtubePrewatch.videoData[id].duration * 1);
      youtubePrewatch.tooltipPreview.src = youtubePrewatch.videoData[id].image;
      youtubePrewatch.tooltipRating.style.width = youtubePrewatch.videoData[id].rating * 15 + "px";
      youtubePrewatch.checkForPreload(id);
    }
    youtubePrewatch.renderTooltipPosition();
  },
  
  /* empties every tooltip element except the title */
  displayEmptyVideoData : function() {
    youtubePrewatch.tooltipDescriptionText.data = "";
    youtubePrewatch.tooltipAuthorText.data = "";
    youtubePrewatch.tooltipPublishedText.data = "";
    youtubePrewatch.tooltipDurationText.data = "";
    youtubePrewatch.tooltipPreview.src = "";
    youtubePrewatch.tooltipRating.style.width = "0";
  },
  
  reciveVideoData : function(request) {
    var text = request.responseText;
    youtubePrewatch.debug(text);
    var data = {
      id         : (/videos\/([\w-]+)<\/id>/.exec(text) || [false,false])[1],
      title      : (/<title type='text'>([^<]+)/.exec(text) || [false,false])[1],
      description: (/<content type='text'>([^<]+)/.exec(text) || [false,false])[1],
      duration   : (/<yt:duration seconds='(\d+)'/.exec(text) || [false,false])[1],
      author     : (/<author><name>([^<]+)/.exec(text) || [false,false])[1],
      image      : (/thumbnail url='([^']+)/.exec(text) || [false,false])[1],
      rating     : (/<gd:rating average='([^']+)/.exec(text) || [false,false])[1],
      published  : (/<published>([^<]+)/.exec(text) || [false,false])[1],
    }
    youtubePrewatch.debug(data);
    for(index in data) {
      if (!data[index]) {
        youtubePrewatch.debug("Ein Element fehlt (" + index + ")")
        return;
      } else {
        data[index] = data[index].replace(/&lt;/, "<").replace(/&gt;/, ">")
            .replace(/&quot;/, "\"").replace(/&amp;/, "&")
      }
    }
    if (data.description.length > 200) {
      data.description = data.description.substr(0, 200).replace(/[^\s]*$/, "") + " ..."
    }
    var dateData = /(\d+)-(\d+)-(\d+)/.exec(data.published);
    data.published = new Date(parseInt(dateData[1]), parseInt(dateData[2]) - 1, 
        parseInt(dateData[3]));
    data.rating = Math.round(data.rating * 2) / 2;
    youtubePrewatch.videoData[data.id] = data;
    youtubePrewatch.displayVideoData();
  },
  
  checkForPreload : function(possibleid) {
    if (youtubePrewatch.currentVideoId != possibleid) {
      //only preload if the request was for the current video
      return;
    }
    if (!GM_getValue("preload", 
            youtubePrewatch.defaultValues["preload"] || false)) {
      //disabled
      return;
    }
    var id = possibleid;
    var timeshiftPercent = GM_getValue("timeshift", youtubePrewatch.defaultValues.timeshift);
    var timeshift = ((youtubePrewatch.videoData[id]|| {duration:0}).duration || 0) * timeshiftPercent / 100;
    if (!id) {
      return;
    }
    youtubePrewatch.debug("Cueing Start time: " + timeshift)
    setTimeout('youtubePrewatch.cueVideo("' 
            + id + '", ' + timeshift + ');', 0);
  },
  
  /**
   * Functions to start/stop page video
   */
  getPageVideoPalyerId : function() {
    if (document.getElementById("movie_player")) {
      return "movie_player"
    }
    return null;
  },
  //stops if settings require it
  //@return if the tooltip should be muted
  pageVideoTooltipShow : function() {
    var action = youtubePrewatch.getSetting("collissionAction");
    var player = youtubePrewatch.getPageVideoPalyerId();
    if (!player) {
      return false;
    } else if (action == "muteSmall") {
      return true;
    } else if (action == "mutePlayer") {
      setTimeout("document.getElementById('" + player + "').mute()", 0);
      return false;
    } else if (action == "pausePlayer") {
      setTimeout("document.getElementById('" + player + "').pauseVideo()", 0);
      return false;
    } else {
      return false;
    }
  },
  //undoes the stop
  pageVideoTooltipHide : function() {
    var action = youtubePrewatch.getSetting("collissionAction");
    var player = youtubePrewatch.getPageVideoPalyerId();
    if (!player) {
    } else if (action == "mutePlayer") {
      setTimeout("document.getElementById('" + player + "').unMute()", 0);
    } else if (action == "pausePlayer") {
      setTimeout("document.getElementById('" + player + "').playVideo()", 0);
    }
  },
  /* SETTINGS */
  /*
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window title="' + getText('settings') + '"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
        xmlns:html="http://www.w3.org/1999/xhtml">
<box style="overflow:auto" orient="vertical" flex="1">

<dialogheader title="' + getText('Timing options') + '" 
    description="' + getText('when to display the tooltip') + '"/>
<vbox style="padding:0 1em 1em">
  <label value="' + getText('display delay') + '" id="displayDelayText" 
      labelsource="display video information after the mouse was %t over the element"/>
  <hbox>
    <spacer flex="1"/>
    <scale min="0" max="100" id="displayDelayScale" flex="2"/>
  </hbox>
  <label value="' + getText('additional play delay') + '" id="playDelayText" 
      labelsource="start playing video %t after the tooltip was displayed"/>
  <hbox>
    <spacer flex="1"/>
    <scale min="0" max="100" id="playDelayScale" flex="2"/>
  </hbox>
  <checkbox label="' + getText('start preloading the video when the tooltip is displayed') + '" id="preloadCheckbox"/>
</vbox>

<dialogheader title="' + getText('Play options') + '" 
    description="' + getText('how to play the mini video') + '"/>
<grid style="padding:0 1em 1em">
  <columns>
    <column flex="1"/>
    <column flex="2"/>
  </columns>
  <rows>
    <row>
      <label value="' + getText('volume') + '" id="volumeText" 
          labelsource="volume: %d%"/>
      <scale min="0" max="100" id="volumeScale"/>
    </row>
    <row>
      <label value="' + getText('timeshift') + '" id="timeshiftText" 
          labelsource="start position: %d%"/>
      <scale min="0" max="100" id="timeshiftScale"/>
    </row>
    <row>
      <label value="' + getText('if a video is played') + '"/>
       <menulist id="collissionActionMenulist">
        <menupopup>
          <menuitem label="' + getText('no action') + '" value="ignore"/>
          <menuitem label="' + getText('mute preview') + '" value="muteSmall"/>
          <menuitem label="' + getText('mute player') + '" value="mutePlayer"/>
          <menuitem label="' + getText('pause player') + '" value="pausePlayer"/>
        </menupopup>
      </menulist>
    </row>
  </rows>
</grid>

<dialogheader title="' + getText('Display') + '" 
    description="' + getText('ho souldd the tooltip look like') + '"/>
<grid style="padding:0 1em 1em">
  <columns>
    <column flex="1"/>
    <column flex="2"/>
  </columns>
  <rows>
    <row>
      <label value="' + getText('Size of the tooltip') + '" id="tooltipSizeLabel" 
        labelsource="Size of the tooltip: %dpx"/>
      <scale min="250" max="500" id="tooltipSize" flex="2"/>
    </row>
    <row>
      <label value="' + getText('Size of the video') + '" id="videoSizeLabel" 
        labelsource="Size of the video: %d%"/>
      <scale min="10" max="60" id="videoSize" flex="2"/>
    </row>
    <row>
      <label value="' + getText('Color theme') + '" id="size"/>
      <scale min="0" max="100" id="playDelayScale" flex="2"/>
       <menulist id="collissionActionMenulist">
        <menupopup>
          <menuitem label="' + getText('blue') + '" value="blue:lighblue"/>
          <menuitem label="' + getText('green') + '" value="green:lightgreen"/>
          <menuitem label="' + getText('red') + '" value="red:lightred"/>
          <menuitem label="' + getText('orange') + '" value="orange:lightorange"/>
          <menuitem label="' + getText('yellow') + '" value="yellow:yellow"/>
          <menuitem label="' + getText('black') + '" value="black:white"/>
        </menupopup>
      </menulist>
    </row>
  </rows>
</grid>
<dialogheader title="' + getText('About') + '" description="Youtube Prewatch 1.0"/>
  <vbox style="padding:0 1em 1em">
    <description>
      ' + getText('%s by %s', 'Youtube Prewatch', '<html:a href="http://userscripts.org/users/michaelz" target="_blank">Michael Z.</html:a>') + '
    </description>
    <description>
      ' + getText('Current Version: %s', '1.0b5') + '
    </description>
    <description>
      ' + getText('Language code (selected by Youtube): %s', document.documentElement.getAttribute('lang') ) + '
    </description>
    <description>
      ' + getText('More information at the scripts %s',
      '<html:a href="http://userscripts.org/scripts/show/55315" target="_blank" title="">' + getText('homepage') + '</html:a>') + ' 
    </description>
</vbox>
<spacer flex="1"/>
<hbox>
  <label value="' + getText('settings are automatically saved') + '"/>
  <spacer flex="1"/><button label="' + getText('close') + '" oncommand="close()"/>
</hbox>
</box>
</window>*/
  settingsWindow : null,
  /**
   * shows a popup with the settings
   */
  showSettings : function() {
    if (youtubePrewatch.settingsWindow != null && !youtubePrewatch.settingsWindow.closed) {
      youtubePrewatch.settingsWindow.focus()
      return;
    }
    
    function getText(text) {
      return i18n.apply(window, arguments);
    }
    
    var settingsCode = 'data:application/vnd.mozilla.xul+xml,'
     + encodeURIComponent('<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window title="' + getText('settings') + '" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"> <box style="overflow:auto" orient="vertical" flex="1"> <dialogheader title="' + getText('Timing options') + '" description="' + getText('when to display the tooltip') + '"/> <vbox style="padding:0 1em 1em"> <label value="' + getText('display delay') + '" id="displayDelayText" labelsource="display video information after the mouse was %t over the element"/> <hbox> <spacer flex="1"/> <scale min="0" max="100" id="displayDelayScale" flex="2"/> </hbox> <label value="' + getText('additional play delay') + '" id="playDelayText" labelsource="start playing video %t after the tooltip was displayed"/> <hbox> <spacer flex="1"/> <scale min="0" max="100" id="playDelayScale" flex="2"/> </hbox> <checkbox label="' + getText('start preloading the video when the tooltip is displayed') + '" id="preloadCheckbox"/> </vbox> <dialogheader title="' + getText('Play options') + '" description="' + getText('how to play the mini video') + '"/> <grid style="padding:0 1em 1em"> <columns> <column flex="1"/> <column flex="2"/> </columns> <rows> <row> <label value="' + getText('volume') + '" id="volumeText" labelsource="volume: %d%"/> <scale min="0" max="100" id="volumeScale"/> </row> <row> <label value="' + getText('timeshift') + '" id="timeshiftText" labelsource="start position: %d%"/> <scale min="0" max="100" id="timeshiftScale"/> </row> <row> <label value="' + getText('if a video is played') + '"/> <menulist id="collissionActionMenulist"> <menupopup> <menuitem label="' + getText('no action') + '" value="ignore"/> <menuitem label="' + getText('mute preview') + '" value="muteSmall"/> <menuitem label="' + getText('mute player') + '" value="mutePlayer"/> <menuitem label="' + getText('pause player') + '" value="pausePlayer"/> </menupopup> </menulist> </row> </rows> </grid> <dialogheader title="' + getText('About') + '" description="Youtube Prewatch 1.0"/> <vbox style="padding:0 1em 1em"> <description> ' + getText('%s by %s', 'Youtube Prewatch', '<html:a href="http://userscripts.org/users/michaelz" target="_blank">Michael Z.</html:a>') + ' </description> <description> ' + getText('Current Version: %s', '1.0b5') + ' </description> <description> ' + getText('Language code (selected by Youtube): %s', document.documentElement.getAttribute('lang') ) + ' </description> <description> ' + getText('More information at the scripts %s', '<html:a href="http://userscripts.org/scripts/show/55315" target="_blank" title="">' + getText('homepage') + '</html:a>') + ' </description> </vbox> <spacer flex="1"/> <hbox> <label value="' + getText('settings are automatically saved') + '"/> <spacer flex="1"/><button label="' + getText('close') + '" oncommand="close()"/> </hbox> </box> </window>');
    youtubePrewatch.settingsWindow = window.open(settingsCode);
    youtubePrewatch.settingsWindow.addEventListener("load", youtubePrewatch.settingsWindowLoad, true);
    youtubePrewatch.settingsWindow.addEventListener("close", function() {
      youtubePrewatch.settingsWindow = null;
    }, true);
  },
  
  /**
   * adds the events to the settings window and initiates all settings
   */
  settingsWindowLoad : function() {
    youtubePrewatch.settingsRegisterScale("playDelay");
    youtubePrewatch.settingsRegisterScale("displayDelay");
    youtubePrewatch.settingsRegisterPercentageScale("volume");
    youtubePrewatch.settingsRegisterPercentageScale("timeshift");
    youtubePrewatch.settingsRegisterMenulist("collissionAction");
    youtubePrewatch.settingsRegisterCheckbox("preload");
  },
  
  /*
   milliseconds = scaleValue ^ 2; 
   */
  settingsRegisterScale : function(settingName) {
    var settingName = settingName;
    var doc = youtubePrewatch.settingsWindow.document;
    var scale = doc.getElementById(settingName + "Scale")
    var scaleText =  doc.getElementById(settingName + "Text")
    var defaultValue = youtubePrewatch.defaultValues[settingName] || 500;
    var milliseconds = GM_getValue(settingName, defaultValue);
    var scaleValue = Math.round(Math.sqrt(milliseconds));
    
    scale.setAttribute("value", scaleValue + "");
    scaleText.setAttribute("value", i18n(scaleText.getAttribute("labelsource"), milliseconds / 1000));
    scale.addEventListener("change", function(evt) {
      var scaleValue = evt.target.getAttribute("value") * 1
      var milliseconds = scaleValue * scaleValue;
      youtubePrewatch.setSetting(settingName, milliseconds);
      scaleText.setAttribute("value", i18n(scaleText.getAttribute("labelsource"), milliseconds / 1000));
    }, true);
  },
  
  settingsRegisterPercentageScale : function(settingName) {
    var settingName = settingName;
    var doc = youtubePrewatch.settingsWindow.document;
    var defaultValue = youtubePrewatch.defaultValues[settingName] || 50;
    var scale = doc.getElementById(settingName + "Scale")
    var scaleText = doc.getElementById(settingName + "Text")
    scale.setAttribute("value", youtubePrewatch.getSetting(settingName));
    scaleText.setAttribute("value", i18n(scaleText.getAttribute("labelsource"),
        scale.getAttribute("value")*1));
    scale.addEventListener("change", function(evt) {
      youtubePrewatch.setSetting(settingName, evt.target.getAttribute("value") * 1);
      scaleText.setAttribute("value", i18n(scaleText.getAttribute("labelsource"),
          scale.getAttribute("value")*1));
    }, true);
  },
  
  settingsRegisterMenulist : function(settingName) {
    var settingName = settingName;
    var doc = youtubePrewatch.settingsWindow.document;
    var defaultValue = youtubePrewatch.defaultValues[settingName] || "";
    var list = doc.getElementById(settingName + "Menulist");
    
    list.setAttribute("value", youtubePrewatch.setSetting(settingName, defaultValue));
    list.addEventListener("command", function(evt) {
      youtubePrewatch.setSetting(settingName, evt.target.getAttribute("value"));
    }, true);
  },

  settingsRegisterCheckbox : function(settingName) {
    var settingName = settingName;
    var doc = youtubePrewatch.settingsWindow.document;
    var checkbox = doc.getElementById(settingName + "Checkbox");
    checkbox.setAttribute("checked", youtubePrewatch.setSetting(settingName, 
            youtubePrewatch.defaultValues[settingName] || false));
    checkbox.addEventListener("command", function(evt) {
      youtubePrewatch.setSetting(settingName, evt.target.getAttribute("checked") == "true");
    }, true);
  }
}
youtubePrewatch.unsafeWindow.youtubePrewatch = {
  registerElement : youtubePrewatch.registerElement,
  debug: youtubePrewatch.debug,
  cuedVideoId : null,
  /* 0: nothing cued/tooltip not displayed, 1: loading and should not play, 2: waying for play command, 3:should play, but still loading, 4:playing */
  cuedVideoStatus: 0,
  youtubePlayer : null,
  youtubePlayerReady : false
}

var unsafeWinText = " \
youtubePrewatch.cueVideo = function(videoid, timeshift /* in s */) { \
  youtubePrewatch.debug('recived cue command for ' + videoid + ' at '+ timeshift); \
  var videoid = videoid, timeshift = timeshift; \
  youtubePrewatch.executeWhenPlayerReady(function() { \
    youtubePrewatch.stopVideo(); \
    youtubePrewatch.debug('cueing: ' + videoid); \
    youtubePrewatch.youtubePlayer.loadVideoById(videoid, timeshift - 0.2, 'small'); \
    /*youtubePrewatch.youtubePlayer.pauseVideo();*/ \
    youtubePrewatch.cuedVideoStatus = 1; \
    youtubePrewatch.cuedVideoId = videoid; \
    youtubePrewatch.youtubePlayer.setVolume(0); \
  }); \
}; \
youtubePrewatch.executeWhenPlayerReady = function(func) { \
  if (!youtubePrewatch.youtubePlayer) { \
    youtubePrewatch.onPlayerLoad = func; \
    youtubePrewatch.loadPlayer(); \
  } else if (!youtubePrewatch.youtubePlayerReady) { \
    youtubePrewatch.onPlayerLoad = func; \
  } else { \
    func(); \
  } \
}; \
youtubePrewatch.startVideo = function(videoid, timeshift /* in s */, volume) { \
  youtubePrewatch.debug('recived start command for ' + videoid + ' at '+ timeshift); \
  var videoid = videoid, timeshift = timeshift; \
  youtubePrewatch.executeWhenPlayerReady(function() { \
    youtubePrewatch.debug('cued:' + youtubePrewatch.cuedVideoId + '; cur: '+ videoid); \
    if (youtubePrewatch.cuedVideoId != videoid) { \
      youtubePrewatch.debug('Wrong/no video was cued.');\
      youtubePrewatch.youtubePlayer.loadVideoById(videoid, timeshift, 'small'); \
      youtubePrewatch.cuedVideoId = videoid; \
      youtubePrewatch.cuedVideoStatus = 4; \
    } else if (youtubePrewatch.cuedVideoStatus == 1){ \
      youtubePrewatch.debug('Marking video to be started once it was load.');\
      youtubePrewatch.cuedVideoStatus = 3; \
    } else if (youtubePrewatch.cuedVideoStatus == 2) { \
      youtubePrewatch.debug('Playing video, because it was load');\
      youtubePrewatch.cuedVideoStatus = 4; \
      youtubePrewatch.youtubePlayer.playVideo(); \
    } else if (youtubePrewatch.cuedVideoStatus == 0) { \
      youtubePrewatch.debug('Video was not cued (staus 0)');\
      youtubePrewatch.youtubePlayer.loadVideoById(videoid, timeshift, 'small'); \
      youtubePrewatch.cuedVideoStatus = 4; \
    } \
    youtubePrewatch.youtubePlayer.setVolume(volume); \
  }); \
}; \
youtubePrewatch.stopVideoTimeout = null; \
youtubePrewatch.stopVideo = function() { \
  youtubePrewatch.debug('recived stop/reset command'); \
  youtubePrewatch.cuedVideoId = null; \
  youtubePrewatch.cuedVideoStatus = 0; \
  try { \
    youtubePrewatch.youtubePlayer.stopVideo(); \
  } catch (e) { \
    try {\
      youtubePrewatch.youtubePlayer.setVolume(0); \
      youtubePrewatch.youtubePlayer.clearVideo(); \
    } catch (e) { \
      if (youtubePrewatch.stopVideoTimeout) {\
        clearTimeout(youtubePrewatch.stopVideoTimeout);\
      }\
      youtubePrewatch.stopVideoTimeout = setTimeout(youtubePrewatch.stopVideo, 200);\
    } \
  }\
}; \
 \
youtubePrewatch.loadPlayer = function() { \
  /*player ready event*/ \
  if (window.onYouTubePlayerReady == 'function') { \
    youtubePrewatch.onYouTubePlayerReadyCascade = window.onYouTubePlayerReady; \
  } \
  window.onYouTubePlayerReady = youtubePrewatch.onYouTubePlayerReady; \
  \
  /*var t = '', fmt_url_map = ''; \
  var pagePlayer = document.getElementById('movie_player'); \
  if (pagePlayer) { \
    var result = /&t=([^&]+)/.exec(pagePlayer.getAttribute('flashvars')); \
    var result = /&fmt_url_map=([^&]+)/.exec(pagePlayer.getAttribute('flashvars')); \
    t = result ? result[1] : ''; \
    fmt_url_map = result ? result[1] : ''; \
  }*/ \
  document.getElementById('youtubePrewatchVideo').innerHTML += \
      '<embed id=\\'youtubePrewatchPlayer\\' height=\\'100%\\' width=\\'100%\\' '\
    + 'type=\\'application/x-shockwave-flash\\' '\
    + 'allowscriptaccess=\\'always\\' allowfullscreen=\\'true\\' '\
    + 'src=\\'http://www.youtube.com/apiplayer?rel=0&loop=1&iv_load_policy=3'\
      + '&enablejsapi=1&playerapiid=youtubePrewatchPlayer\\'>'; \
  youtubePrewatch.youtubePlayer \
                   = document.getElementById('youtubePrewatchPlayer'); \
}; \
\
youtubePrewatch.playerStatusChange = function(state) { \
  youtubePrewatch.debug('player state: ' + state + ', cue status: ' + youtubePrewatch.cuedVideoStatus);\
  if (state == 1) { \
    if (youtubePrewatch.cuedVideoStatus == 1) {\
      youtubePrewatch.debug('cued video was load. Pausing it until it has to be played.');\
      youtubePrewatch.cuedVideoStatus = 2; \
      youtubePrewatch.youtubePlayer.pauseVideo(); \
    } else if (youtubePrewatch.cuedVideoStatus == 3) {\
      youtubePrewatch.debug('cued video was finally load. It should be played now.');\
      youtubePrewatch.cuedVideoStatus = 4; \
    } else if (youtubePrewatch.cuedVideoStatus == 0) { \
      youtubePrewatch.debug('cued video was finally load, but has not to be played. stopping it.');\
      youtubePrewatch.youtubePlayer.pauseVideo(); \
      youtubePrewatch.youtubePlayer.stopVideo(); \
    }\
  } \
}; \
youtubePrewatch.onYouTubePlayerReadyCascade = function() {}; \
youtubePrewatch.onYouTubePlayerReady = function(playerId) { \
  if (playerId == 'youtubePrewatchPlayer') { \
    youtubePrewatch.youtubePlayerReady = true; \
    youtubePrewatch.onPlayerLoad(); \
    youtubePrewatch.onPlayerLoad = function(){}; \
    youtubePrewatch.youtubePlayer.addEventListener('onStateChange', \
      'youtubePrewatch.playerStatusChange'); \
  } else { \
    youtubePrewatch.onYouTubePlayerReadyCascade(playerId); \
  } \
}; ";
youtubePrewatch.unsafeWindow.setTimeout(unsafeWinText, 0);

youtubePrewatch.init();
if (GM_registerMenuCommand) {
  GM_registerMenuCommand(i18n("youtube prewatch: ") + i18n("settings"), youtubePrewatch.showSettings)
}