YouTube Auto Buffer & Auto HD

By JoeSimmons Last update May 22, 2013 — Installed 628,819 times.

There are 61 previous versions of this script.

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

// ==UserScript==
// @name           YouTube Auto Buffer & Auto HD
// @namespace      http://userscripts.org/users/23652
// @description    Buffers the video without autoplaying and puts it in HD if the option is on. For Firefox, Opera, & Chrome
// @include        http://*.youtube.com/*
// @include        http://youtube.com/*
// @include        https://*.youtube.com/*
// @include        https://youtube.com/*
// @copyright      JoeSimmons
// @version        1.2.72
// @license        http://creativecommons.org/licenses/by-nc-nd/3.0/us/
// @require        http://usocheckup.dune.net/49366.js
// @grant          GM_getValue
// @grant          GM_log
// @grant          GM_openInTab
// @grant          GM_registerMenuCommand
// @grant          GM_setValue
// @grant          GM_xmlhttpRequest
// ==/UserScript==

/* RELEASE NOTES

1.2.72
	- Made it fully working again in Opera & Chrome
	- Switched from setInterval to setTimeout due to instability

1.2.71
	- Added compatibility for HTML5

*/

var navID = "watch7-user-header";

// Make sure it's running on the main page, no frames
var unsafeWindow = unsafeWindow || window.wrappedJSObject || window,
	noGo = false;
try {
	if(unsafeWindow.frameElement !== null) noGo = true;
} catch(e) {}

// $g by JoeSimmons. Supports ID, Class, and XPath (full with types) in one query
// Supports multiple id/class grabs in one query (split by spaces), and the ability to remove all nodes regardless of type
// See script page for syntax examples: http://userscripts.org/scripts/show/51532
function $g(que, O) {

	if(!que || typeof que !== "string" || que === "" || !(que=que.replace(/^\s+/,''))) return false;
	var obj = O || ({del:false, type:6, node:document}), r, t,
		idclass_re = /^[#\.](?!\/)[^\/]/,
		xp_re=/^\.?(\/{1,2}|count|id)/;

	if(idclass_re.test(que)) {
		var s=que.split(" "), r=new Array(), c;
		for(var n=0; n<s.length; n++) {
			switch(s[n].substring(0,1)) {
			
				case "#": r.push(document.getElementById(s[n].substring(1))); break;
				
				case ".": c=document.getElementsByClassName(s[n].substring(1));
					if(c.length>0) for(var i=0; i<c.length; i++) r.push(c[i]); break;
			}
		}
		if(r.length==1) r=r[0];
	} else if(xp_re.test(que)) {
		r = (obj["doc"] || document).evaluate(que, (obj['node']||document), null, ((t=obj['type']) || 6), null);
		if(typeof t === "number" && /[12389]/.test(t)) r = r[(t === 1 ? "number" : (t === 2 ? "string" : (t === 3 ? "boolean" : "singleNode"))) + "Value"];
	}

	if(r && obj["del"] === true) {
		if(r.nodeType === 1) r.parentNode.removeChild(r);
			else if(r.snapshotItem) for(var i=r.snapshotLength-1; (item=r.snapshotItem(i)); i--) item.parentNode.removeChild(item);
			else if(!r.snapshotItem) for(var i=r.length-1; i>=0; i--) if(r[i]) r[i].parentNode.removeChild(r[i]);
	} return r;

}

var GM_config = {
 storage: 'GM_config', // This needs to be changed to something unique for localStorage
 init: function() {
        // loop through GM_config.init() arguments
	for(var i=0,l=arguments.length,arg; i<l; ++i) {
		arg=arguments[i];
		switch(typeof arg) {
            case 'object': for(var j in arg) { // could be a callback functions or settings object
							switch(j) {
							case "open": GM_config.onOpen=arg[j]; delete arg[j]; break; // called when frame is gone
							case "close": GM_config.onClose=arg[j]; delete arg[j]; break; // called when settings have been saved
							case "save": GM_config.onSave=arg[j]; delete arg[j]; break; // store the settings objects
							default: var settings = arg;
							}
			} break;
            case 'function': GM_config.onOpen = arg; break; // passing a bare function is set to open
                        // could be custom CSS or the title string
			case 'string': if(arg.indexOf('{') !== -1 && arg.indexOf('}') !== -1) var css = arg;
				else GM_config.title = arg;
				break;
		}
	}
	if(!GM_config.title) GM_config.title = 'Settings - Anonymous Script'; // if title wasn't passed through init()

	// give the script a unique saving ID for non-firefox browsers
	GM_config.storage = GM_config.title.replace(/\W+/g, "").toLowerCase();

	var stored = GM_config.read(); // read the stored settings
	GM_config.passed_values = {};
	for(var i in settings) {
		GM_config.doSettingValue(settings, stored, i, null, false);
		if(settings[i].kids) for(var kid in settings[i].kids) GM_config.doSettingValue(settings, stored, kid, i, true);
	}
	GM_config.values = GM_config.passed_values;
	GM_config.settings = settings;
	if (css) GM_config.css.stylish = css;
 },
 open: function() {
 if(document.evaluate("//iframe[@id='GM_config']",document,null,9,null).singleNodeValue) return;
	// Create frame
	document.body.appendChild((GM_config.frame=GM_config.create('iframe',{id:'GM_config', style:'position:fixed; top:0; left:0; opacity:0; display:none; z-index:999; width:75%; height:75%; max-height:95%; max-width:95%; border:1px solid #000000; overflow:auto;'})));
        GM_config.frame.src = 'about:blank'; // In WebKit src cant be set until it is added to the page
	GM_config.frame.addEventListener('load', function(){
		var obj = GM_config, frameBody = this.contentDocument.getElementsByTagName('body')[0], create=obj.create, settings=obj.settings;
		obj.frame.contentDocument.getElementsByTagName('head')[0].appendChild(create('style',{type:'text/css',textContent:obj.css.basic+obj.css.stylish}));

		// Add header and title
		frameBody.appendChild(create('div', {id:'header',className:'config_header block center', innerHTML:obj.title}));

		// Append elements
		var anch = frameBody, secNo = 0; // anchor to append elements
		for (var i in settings) {
			var type, field = settings[i], value = obj.values[i];
			if (field.section) {
				anch = frameBody.appendChild(create('div', {className:'section_header_holder', id:'section_'+secNo, kids:new Array(
				  create('a', {className:'section_header center', href:"javascript:void(0);", id:'c_section_kids_'+secNo, textContent:field.section[0], onclick:function(){GM_config.toggle(this.id.substring(2));}}),
				  create('div', {id:'section_kids_'+secNo, className:'section_kids', style:obj.getValue('section_kids_'+secNo, "")==""?"":"display: none;"})
				  )}));
				if(field.section[1]) anch.appendChild(create('p', {className:'section_desc center',innerHTML:field.section[1]}));
				secNo++;
			}
			anch.childNodes[1].appendChild(GM_config.addToFrame(field, i, false));
		}

		// Add save and close buttons
		frameBody.appendChild(obj.create('div', {id:'buttons_holder', kids:new Array(
			obj.create('button',{id:'saveBtn',textContent:'Save',title:'Save options and close window',className:'saveclose_buttons',onclick:function(){GM_config.close(true)}}),
			obj.create('button',{id:'cancelBtn', textContent:'Cancel',title:'Close window',className:'saveclose_buttons',onclick:function(){GM_config.close(false)}}),
			obj.create('div', {className:'reset_holder block', kids:new Array(
				obj.create('a',{id:'resetLink',textContent:'Restore to default',href:'#',title:'Restore settings to default configuration',className:'reset',onclick:obj.reset})
		)}))}));

		obj.center(); // Show and center it
		window.addEventListener('resize', obj.center, false); // Center it on resize
		if (obj.onOpen) obj.onOpen(); // Call the open() callback function
		
		// Close frame on window close
		window.addEventListener('beforeunload', function(){GM_config.remove(this);}, false);
	}, false);
 },
 close: function(save) {
	if(save) {
		var type, fields = GM_config.settings, typewhite=/radio|text|hidden|checkbox/;
		for(f in fields) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
			if(typewhite.test(field.type)) type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doSave(f, field, type);
			if(kids) for(var kid in kids) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
			if(typewhite.test(field.type)) type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doSave(kid, field, type, f);
			}
		}
                if(GM_config.onSave) GM_config.onSave(); // Call the save() callback function
                GM_config.save();
	}
	if(GM_config.frame) GM_config.remove(GM_config.frame);
	delete GM_config.frame;
        if(GM_config.onClose) GM_config.onClose(); //  Call the close() callback function
 },
 set: function(name,val) {
	GM_config.values[name] = val;
 },
 get: function(name) {
	return GM_config.values[name];
 },
 isGM: typeof GM_getValue !== 'undefined' && typeof GM_getValue('a', 'b') !== 'undefined',
 log: (this.isGM) ? GM_log : ((window.opera) ? opera.postError : console.log),
 getValue : function(name, def) { return (this.isGM?GM_getValue:(function(name,def){return localStorage.getItem(name)||def}))(name, def||""); },
 setValue : function(name, value) { return (this.isGM?GM_setValue:(function(name,value){return localStorage.setItem(name,value)}))(name, value||""); },
 save: function(store, obj) {
    try {
		var val = JSON.stringify(obj || GM_config.values);
		GM_config.setValue((store||GM_config.storage),val);
    } catch(e) {
		GM_config.log("GM_config failed to save settings!\n" + e);
    }
 },
 read: function(store) {
	var val = GM_config.getValue((store || GM_config.storage), '{}');
	switch(typeof val) {
		case "string": var rval = JSON.parse(val); break;
		case "object": var rval = val; break;
		default: var rval = {};
	}
    return rval;
 },
 reset: function(e) {
	e.preventDefault();
	var type, obj = GM_config, fields = obj.settings;
	for(f in fields) {
		var field = obj.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
		if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
		else type=field.tagName.toLowerCase();
		GM_config.doReset(field, type, null, f, null, false);
		if(kids) for(var kid in kids) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
			if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doReset(field, type, f, kid, true);
		}
	}
 },
 addToFrame : function(field, i, k) {
	var elem, obj = GM_config, anch = GM_config.frame, value = obj.values[i], Options = field.options, label = field.label, create=GM_config.create, isKid = k!=null && k===true;
		switch(field.type) {
				case 'textarea':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('textarea', {id:'field_'+i,innerHTML:value, cols:(field.cols?field.cols:20), rows:(field.rows?field.rows:2)})
					), className: 'config_var'});
					break;
				case 'radio':
					var boxes = new Array();
					for (var j = 0,len = Options.length; j<len; j++) {
						boxes.push(create('span', {textContent:Options[j]}));
						boxes.push(create('input', {value:Options[j], type:'radio', name:i, checked:Options[j]==value?true:false}));
					}
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('span', {id:'field_'+i, kids:boxes})
					), className: 'config_var'});
					break;
				case 'select':
					var options = new Array();
					if(!Options.inArray) for(var j in Options) options.push(create('option',{textContent:Options[j],value:j,selected:(j==value)}));
						else options.push(create("option", {textContent:"Error - options needs to be an object type, not an array.",value:"error",selected:"selected"}));
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('select',{id:'field_'+i, kids:options})
					), className: 'config_var'});
					break;
				case 'checkbox':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('label', {textContent:label, className:'field_label', "for":'field_'+i}),
						create('input', {id:'field_'+i, type:'checkbox', value:value, checked:value})
					), className: 'config_var'});
					break;
				case 'button':
				var tmp;
					elem = create(isKid ? "span" : "div", {kids:new Array(
						(tmp=create('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:field.title||''}))
					), className: 'config_var'});
					if(field.script) obj.addEvent(tmp, 'click', field.script);
					break;
				case 'hidden':
				elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('input', {id:'field_'+i, type:'hidden', value:value})
					), className: 'config_var'});
					break;
				default:
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('input', {id:'field_'+i, type:'text', value:value, size:(field.size?field.size:25)})
					), className: 'config_var'});
			}
	if(field.kids) {
	var kids=field.kids;
	for(var kid in kids) elem.appendChild(GM_config.addToFrame(kids[kid], kid, true));
	}
return elem;
},
 doSave : function(f, field, type, oldf) {
 var isNum=/^[\d\.]+$/, set = oldf ? GM_config.settings[oldf]["kids"] : GM_config.settings;
 switch(type) {
				case 'text':
					GM_config.values[f] = ((set[f].type=='text') ? field.value : ((isNum.test(field.value) && ",int,float".indexOf(","+set[f].type)!=-1) ? parseFloat(field.value) : false));
					if(set[f]===false) {
						alert('Invalid type for field: '+f+'\nPlease use type: '+set[f].type);
						return;
					}
					break;
				case 'hidden':
					GM_config.values[f] = field.value.toString();
					break;
				case 'textarea':
					GM_config.values[f] = field.value;
					break;
				case 'checkbox':
					GM_config.values[f] = field.checked;
					break;
				case 'select':
					GM_config.values[f] = field.options[field.selectedIndex].value;
					break;
				case 'span':
					var radios = field.getElementsByTagName('input');
					if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
						if(radios[i].checked) GM_config.values[f] = radios[i].value;
					}
					break;
			}
 },
 doSettingValue : function(settings, stored, i, oldi, k) {
		var set = k!=null && k==true && oldi!=null ? settings[oldi]["kids"][i] : settings[i];
			if(",save,open,close".indexOf(","+i) == -1) {
            // The code below translates to:
            // if a setting was passed to init but wasn't stored then 
            //      if a default value wasn't passed through init() then use null
            //      else use the default value passed through init()
            // 		else use the stored value
            try {
            var value = (stored[i]==undefined ? (set["default"]==undefined ? null : set["default"]) : stored[i]);
			} catch(e) {
			var value = (stored[i]=="undefined" ? (set["default"]=="undefined" ? null : set["default"]) : stored[i]);
			}
            
            // If the value isn't stored and no default was passed through init()
            // try to predict a default value based on the type
            if (value === null) {
                switch(set["type"]) {
                    case 'radio': case 'select':
                        value = set.options[0]; break;
                    case 'checkbox':
                        value = false; break;
                    case 'int': case 'float':
                        value = 0; break;
                    default:
					value = (typeof stored[i]=="function") ? stored[i] : "";
                }
			}
			
			}
	GM_config.passed_values[i] = value;
 },
 doReset : function(field, type, oldf, f, k) {
 var isKid = k!=null && k==true, obj=GM_config,
	 set = isKid ? obj.settings[oldf]["kids"][f] : obj.settings[f];
 switch(type) {
			case 'text':
				field.value = set['default'] || '';
				break;
			case 'hidden':
				field.value = set['default'] || '';
				break;
			case 'textarea':
				field.value = set['default'] || '';
				break;
			case 'checkbox':
				field.checked = set['default'] || false;
				break;
			case 'select':
				if(set['default']) {
					for(var i=field.options.length-1; i>=0; i--)
					if(field.options[i].value==set['default']) field.selectedIndex=i;
				}
				else field.selectedIndex=0;
				break;
			case 'span':
				var radios = field.getElementsByTagName('input');
				if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
					if(radios[i].value==set['default']) radios[i].checked=true;
				}
				break;
		}
 },
 values: {},
 settings: {},
 css: {
 basic: 'body {background:#FFFFFF;}\n' +
 '.indent40 {margin-left:40%;}\n' +
 '* {font-family: arial, tahoma, sans-serif, myriad pro;}\n' +
 '.field_label {font-weight:bold; font-size:12px; margin-right:6px;}\n' +
 '.block {display:block;}\n' +
 '.saveclose_buttons {\n' +
 'margin:16px 10px 10px 10px;\n' +
 'padding:2px 12px 2px 12px;\n' +
 '}\n' +
 '.reset, #buttons_holder, .reset a {text-align:right; color:#000000;}\n' +
 '.config_header {font-size:20pt; margin:0;}\n' +
 '.config_desc, .section_desc, .reset {font-size:9pt;}\n' +
 '.center {text-align:center;}\n' +
 '.section_header_holder {margin-top:8px;}\n' +
 '.config_var {margin:0 0 4px 0; display:block;}\n' +
 '.section_header {font-size:13pt; background:#414141; color:#FFFFFF; border:1px solid #000000; margin:0;}\n' +
 '.section_desc {font-size:9pt; background:#EFEFEF; color:#575757; border:1px solid #CCCCCC; margin:0 0 6px 0;}\n' +
 'input[type="radio"] {margin-right:8px;}',
 stylish: ''},
 create: function(a,b) {
	var ret=window.document.createElement(a);
	if(b) for(var prop in b) {
		if(prop.indexOf('on')==0) ret.addEventListener(prop.substring(2),b[prop],false);
		else if(prop=="kids" && (prop=b[prop])) for(var i=0; i<prop.length; i++) ret.appendChild(prop[i]);
		else if(",style,accesskey,id,name,src,href,for".indexOf(","+prop.toLowerCase())!=-1) ret.setAttribute(prop, b[prop]);
		else ret[prop]=b[prop];
	}
	return ret;
 },
 center: function() {
	var node = GM_config.frame, style = node.style, beforeOpacity = style.opacity;
	if(style.display=='none') style.opacity='0';
	style.display = '';
	style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
	style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
	style.opacity = '1';
 },
 run: function() {
    var script=GM_config.getAttribute('script');
    if(script && typeof script=='string' && script!='') {
      func = new Function(script);
      window.setTimeout(func, 0);
    }
 },
 addEvent: function(el,ev,scr) { el.addEventListener(ev, function() { typeof scr == 'function' ? window.setTimeout(scr, 0) : eval(scr) }, false); },
 remove: function(el) { if(el && el.parentNode) el.parentNode.removeChild(el); },
 toggle : function(e) {
	var node=GM_config.frame.contentDocument.getElementById(e);
	node.style.display=(node.style.display!='none')?'none':'';
	GM_config.setValue(e, node.style.display);
 },
};

// Allow opera to use the GM functions, but re-written (from TarquinWJ)
if(window.opera) {
	GM_xmlhttpRequest = XMLHttpRequest;
	GM_log = opera.postError;
	window._content = window;
	function GM_setValue( cookieName, cookieValue, lifeTime ) {
		if( !cookieName ) { return; }
		if( lifeTime == "delete" ) { lifeTime = -10; } else { lifeTime = 31536000; }
		document.cookie = escape( cookieName ) + "=" + escape( cookieValue ) +
			";expires=" + ( new Date( ( new Date() ).getTime() + ( 1000 * lifeTime ) ) ).toGMTString() + ";path=/";
	}
	function GM_getValue( cookieName, oDefault ) {
		var cookieJar = document.cookie.split( "; " );
		for( var x = 0; x < cookieJar.length; x++ ) {
			var oneCookie = cookieJar[x].split( "=" );
			if( oneCookie[0] == escape( cookieName ) ) {
				try {
					eval('var footm = '+unescape( oneCookie[1] ));
				} catch(e) { return oDefault; }
				return footm;
			}
		}
		return oDefault;
	}
	function GM_deleteValue( oKey ) {
		GM_setValue( oKey, '', 'delete' );
	}
}

// Get ID
function $(ID,root) {return (root||document).getElementById(ID);}

// Created by avg, modified by JoeSimmons
function create(a,b,c) {
	if(a=="text") {return document.createTextNode(b);}
	var ret=document.createElement(a.toLowerCase());
	if(b) for(var prop in b) if(prop.indexOf("on")==0) ret.addEventListener(prop.substring(2),b[prop],false);
		else if(",style,accesskey,id,name,src,href".indexOf(","+prop.toLowerCase())!=-1) ret.setAttribute(prop.toLowerCase(), b[prop]);
		else ret[prop]=b[prop];
	if(c) for(var i=0,l=c.length; i<l; i++) ret.appendChild(c[i]);
	return ret;
}

// setVar by JoeSimmons
// Syntax: "autoplay=1&hq=0&ads=1".setVar("ads", "0").setVar("hq", "1");
String.prototype.setVar = function(q, v) {
var regex = new RegExp("([\&\?])?"+q+"=[^\&\#]*", "g");
return regex.test(this) ? this.replace(regex, "$1"+q+"="+v) : this+"&"+q+"="+v;
}

String.prototype.getPref = function(s, splitter) {
return this.split(s+"=")[1].split((splitter||"&"))[0];
};

String.prototype.find = function(s) {
return (this.indexOf(s) != -1);
};

function addScript(s, id) {
	var head = document.getElementsByTagName("head")[0],
		aS = document.createElement("script");
	if(!head) {return;}
	aS.setAttribute("type", "text/javascript");
	aS.setAttribute("id", id);
	try {aS.innerHTML = s;} catch(e) {aS.innerText = s;}
	head.appendChild(aS);
}

function main(GM_config) {

	function create(a,b,c) {
		if(a=="text") {return document.createTextNode(b);}
		var ret=document.createElement(a.toLowerCase());
		if(b) for(var prop in b) if(prop.indexOf("on")==0) ret.addEventListener(prop.substring(2),b[prop],false);
			else if(",style,accesskey,id,name,src,href,which,rel,action,method,value".indexOf(","+prop.toLowerCase())!=-1) ret.setAttribute(prop.toLowerCase(), b[prop]);
			else ret[prop]=b[prop];
		if(c) c.forEach(function(e) { ret.appendChild(e); });
		return ret;
	}

	// Debug by JoeSimmons
	function debug(s) {
		var d=$("debugT");
		
		if(!d) document.body.insertBefore(d=create("textarea", {id:"debugT",style:"margin: 0 1% 6px 1%; padding: 5px; position: inline; width: 97%; height: 20%; color: #000000; background: #E6F4FF; border:3px double #0099FF; border-top: 0; z-index:99999; overflow: scroll !important;",ondblclick:function(e){e.target.style.display="none";}}, new Array(create("text", "[Debug Window 2.0 - Drag box to read fully - Copyright Joe Simmons \"CC BY-ND 3.0\"]\n\n\n\n" + s))), document.body.firstChild);
			else d.innerHTML+="\n\n--------------------------------------------------\n\n"+s;

		if(d.style.display=="none") d.style.display="";
		
		return true;
	}

	GM_config.init("YouTube Auto Buffer Options", {
		autoBuffer : {
			label : "Auto[Buffer/Play]",
			type : "select",
			section : ["Main Options"],
			options : {
				"buffer" : "Autobuffer",
				"play" : "Autoplay",
				"none" : "Both off"
			},
			"default" : "buffer"
		},
		autoHD : {
			label : "Auto HD",
			type : "select",
			options : {
				"240p" : "240p",
				"360p" : "360p (normal)",
				"480p" : "480p",
				"720p" : "720p (HD)",
				"1080p" : "1080p (HD)"
			},
			"default" : "720p"
		},
		volume : {
			label : "Set volume to: ",
			type : "select",
			options : {
				1000 : "Disabled (no effect)",
				0 : "Off",
				5 : "5%",
				10 : "10%",
				20 : "20%",
				25 : "25% (quarter)",
				30 : "30%",
				40 : "40%",
				50 : "50% (half)",
				60 : "60%",
				70 : "70%",
				75 : "75% (three quarters",
				80 : "80%",
				90 : "90%",
				100 : "100% (full)",
			},
			title : "What to set the volume to",
			"default" : 1000
		},
		hideAnnotations : {
			label : "Hide annotations?",
			type : "checkbox",
			"default" : true
		}
	}, "#config_header {font-size:16pt !important;} .config_var {margin-left:20% !important;} #header {margin-bottom:30px !important;} .indent40 {margin-left:20% !important;}", {
	open : function(){ var frame=GM_config.frame; frame.style.height="50%";frame.style.width="50%"; GM_config.center(); }
	});

	$(navID).appendChild(create("button", {id: "autobuffer-options", style: "border: 1px solid #CCCCCC; border-radius: 2px 2px 2px 2px; font-weight: bold; vertical-align: middle; cursor: pointer; background: transparent !important;", className:"yt-uix-button yt-uix-button-text yt-uix-tooltip", type: "button", onclick:GM_config.open},
		[create("span", {className:"yt-uix-button-content", textContent: "Autobuffer Options", title: "Click here to set default Autobuffer options"})]));
		
		// showAllProperties by JoeSimmons
		function showAllProperties(e) {
			var props = "Element Properties:\n\n";
			for(var i=0, p; (p=e.attributes[i]); i++) {
				if(p.value !== undefined) props += p.name + " -> " + p.value + "\n";
			}
			return props;
		}
		
		// Determine if the video player is HTML5 or Flash
		var h5e = $g("//video[contains(@class, 'html5-main-video') and @src and @style]", {type: 9});
		if(h5e !== null) {
			h5e.pause(); // try to pause the html5 player
			if(h5e.currentTime <= 3) h5e.currentTime = 0; // try to reset the time on the html5 player
		} else {

			var mp = $("movie_player"),
				mpC = mp.cloneNode(true),
				regex = {
					ads:/[&\?]?(ad_(tag)?|infringe|watermark)((?!url)[=]*)?=[&]*/gi,
					begin_end:/(^[\&\?]*)|([\&\?]*$)/g
				},
				opHD = GM_config.get("autoHD"),
				volume = parseInt(GM_config.get("volume"), 10),
				fv = mpC.getAttribute("flashvars").setVar("autoplay", (GM_config.get("autoBuffer")=="play"?"1":"0")).setVar("enablejsapi", "1").setVar("fs", "1").setVar("iv_load_policy", (GM_config.get("hideAnnotations")===true?"3":"1"));

			// find the right/best quality according to the options
			switch(opHD) {
				case "240p": fv = fv.setVar("vq", "small"); break;
				case "360p": fv = fv.setVar("vq", "medium"); break;
				case "480p": fv = fv.setVar("vq", "large"); break;
				case "720p": fv = fv.setVar("vq", "hd720"); break;
				case "1080p": fv = fv.setVar("vq", "hd1080"); break;
				default: fv = fv.setVar("vq", "medium");
			}
			/*
			if(GM_config.get("hideAds") === true) {
				fv = fv.replace(/([&\?])?(afv_ad_tag(_restricted_to_instream)?|ad_channel_code_instream|afv_inslate_ad_tag|ad_host(_tier)?|ad_(slots|flags|device|eurl|tag)|ad_video_pub_id|ad_preroll|afv_inslate_ad_tag|adsense_video_doc_id|aftv?|ad_channel_code_overlay|watermark|xfp_tag|ad3_module)=[^&]+/gi, "").setVar("invideo", "false");
			}
			*/
			//debug(fv.split("&").join("\n\n"));

			mpC.setAttribute("flashvars", fv.replace(regex["begin_end"],""));
			mp.parentNode.replaceChild(mpC, mp);

			function onYouTubePlayerReady(playerId) {
				g_YouTubePlayerIsReady=true;
				var mp = document.getElementById("movie_player"),
				startTime = mp.getCurrentTime();
			
				// Add the event listeners so functions get executed when the player state/format changes
				mp.addEventListener("onStateChange","stateChange");
				mp.addEventListener("onPlaybackQualityChange","onPlayerFormatChanged");
			
				// Play the video if autobuffer enabled, otherwise just set volume
				if(autobuffer === "buffer") mp.playVideo();
					else if(volume !== 1000) mp.setVolume(volume);
			}

			function stateChange() {
				var state = document.getElementById("movie_player").getPlayerState();
				switch(state) {
					case 1: // 1 = playing
						if(alreadyBuffered === false && autobuffer === "buffer") {
							var mp=document.getElementById("movie_player"),
								vol=mp.getVolume(), // get the current player volume
								muted=mp.isMuted(), // check if it's muted or not
								startTime = mp.getCurrentTime(); // get the current player time

							// Pause the video so it can buffer
							mp.pauseVideo();
							
							// Set the volume to the user's preference
							mp.setVolume((volume !== 1000 ? volume : vol));

							// Seek back to the beginning, or pre-defined starting time (url #t=xx)
							mp.seekTo((startTime <= 3 ? 0 : startTime), true);

							// Make sure it doesn't auto-buffer again when you press play
							alreadyBuffered = true;
						}
						
					break;
				}
			}
			addScript("var alreadyBuffered = false, volume = "+volume+", autobuffer = \""+GM_config.get("autoBuffer")+"\";\n\n"+onYouTubePlayerReady+"\n\n"+stateChange, "stateChange");
		
		}

}


if(location.href.find("#t=")) location.href = location.href.replace("#t=", "&t=");


// This function waits for the navbar and movie player to
// be ready before starting
function waitForReady(GMC) {
	if($(navID) !== null && $g("//embed[@id='movie_player'] | //video[contains(@class, 'html5-main-video') and @src and @style]", {type: 9}) !== null) {
		main(GMC);
	} else if($(navID) === null || $g("//embed[@id='movie_player'] | //video[contains(@class, 'html5-main-video') and @src and @style]", {type: 9}) === null) {
		sec++;
		if(sec < 100) window.setTimeout(function() {waitForReady(GMC);}, 100);
	}
}

// Quit if the "Autobuffer Options" button already exists
if(noGo === false && $("autobuffer-options") === null) window.setTimeout(function() {waitForReady(GM_config);}, 100), sec=0;